1 #include <gtk/gtk.h> // -*- tab-width:2 coding: viscii mode: c++ -*-
14 class MyText
: public Text
17 MyText(VSpell
* vs
):Text(vs
) {}
22 virtual bool ui_syllable_check();
23 virtual bool ui_word_check();
25 void show_wrong_syllables(unsigned p
);
27 void show_wrong_words(unsigned p
);
29 void iter_at(GtkTextIter
&iter
,int pos
);
30 string
word_to_utf8(unsigned seg_id
);
33 class MyTextFactory
: public TextFactory
36 Text
* create(VSpell
*vs
) const {
37 return new MyText(vs
);
41 static GtkTextTagTable
*tagtable_main
;
42 static GtkTextBuffer
*textbuffer_main
;
43 static GtkWidget
*textview_main
;
44 static GtkWidget
*log_main
;
45 static GtkWidget
*spell_entry
;
46 static GtkWidget
*ignore_button
,*ignore_all_button
,*spell_button
,*open_button
;
47 static GtkListStore
*list_store
;
48 static MyTextFactory myfactory
;
49 static VSpell
vspell(myfactory
);
50 static bool word_boundaries
;
52 static void text_reset(GtkTextBuffer
*textbuffer_main
)
54 GtkTextIter start
,end
;
55 gtk_text_buffer_get_start_iter(textbuffer_main
,&start
);
56 gtk_text_buffer_get_end_iter(textbuffer_main
,&end
);
57 gtk_text_buffer_remove_all_tags (textbuffer_main
, &start
,&end
);
60 void MyText::iter_at(GtkTextIter
&iter
,int pos
)
62 gtk_text_buffer_get_iter_at_offset(textbuffer_main
,&iter
,offset
+pos
);
65 void MyText::show_wrong_syllables(unsigned p
)
67 Suggestions
&sugg
= suggestions
;
68 int cc
,ii
,nn
,i
,n
= sugg
.size();
69 gtk_text_buffer_set_text (textbuffer_main
,
70 vspell
->get_utf8_text().c_str(),
71 strlen(vspell
->get_utf8_text().c_str()));
72 GtkTextIter start
,end
;
75 gtk_text_buffer_apply_tag_by_name(textbuffer_main
,
76 "bg-syllable", &start
, &end
);
77 for (i
= 0;i
< n
;i
++) {
79 int from
= st
[id
].start
;
80 int len
= strlen(get_ngram()[st
[id
].id
]);
81 printf("Syllable Mispelled: %d (%s) at %d\n",
82 id
,get_ngram()[st
[id
].id
],from
);
84 iter_at(end
,from
+len
);
85 gtk_text_buffer_apply_tag_by_name (textbuffer_main
,
86 (i
== p
? "mispelled" : "mispelled2"),
91 void MyText::show_words()
94 GtkTextIter start
,end
;
98 for (i
= 0;i
< n
;i
++) {
99 nn
= seg
[i
].node
.node
->get_syllable_count();
100 if (nn
== 1 && !word_boundaries
) {
104 int from
= st
[cc
].start
;
105 int to
= st
[cc
+nn
-1].start
+strlen(get_ngram()[st
[cc
+nn
-1].id
]);
106 printf("From %d to %d(%d)\n",from
,to
,n
);
109 gtk_text_buffer_apply_tag_by_name (textbuffer_main
, "word",
115 void MyText::show_wrong_words(unsigned p
)
118 GtkTextIter start
,end
;
120 Suggestions
&sugg
= suggestions
;
121 gtk_text_buffer_set_text (textbuffer_main
,
122 vspell
->get_utf8_text().c_str(),
123 strlen(vspell
->get_utf8_text().c_str()));
126 gtk_text_buffer_apply_tag_by_name(textbuffer_main
,
127 "bg-word", &start
, &end
);
131 for (i
= 0;i
< n
;i
++) {
133 for (cc
= ii
= 0;ii
< id
;ii
++)
134 cc
+= seg
[ii
].node
.node
->get_syllable_count();
136 nn
= seg
[id
].node
.node
->get_syllable_count();
138 int from
= st
[cc
].start
;
139 int to
= st
[cc
+nn
-1].start
+strlen(get_ngram()[st
[cc
+nn
-1].id
]);
140 printf("Mispelled at %d\n",id
);
143 gtk_text_buffer_apply_tag_by_name (textbuffer_main
,
144 (i
== p
? "mispelled" : "mispelled2"),
149 static void button_reset_callback (GtkWidget
*button
, gpointer data
)
151 text_reset(textbuffer_main
);
154 static bool is_checking
= true;
155 static bool ignore
= false;
156 static bool ignore_all
= false;
157 static bool processed
= false;
159 static void set_state(bool spellcheck
)
161 GtkTextIter start
,end
;
163 if (spellcheck
== is_checking
)
166 is_checking
= spellcheck
;
167 if (is_checking
|| !word_boundaries
) {
168 gtk_text_buffer_get_start_iter(textbuffer_main
,&start
);
169 gtk_text_buffer_get_end_iter(textbuffer_main
,&end
);
170 gtk_text_buffer_remove_all_tags (textbuffer_main
, &start
,&end
);
173 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview_main
),!is_checking
);
174 gtk_widget_set_sensitive(GTK_WIDGET(open_button
),!is_checking
);
175 gtk_widget_set_sensitive(GTK_WIDGET(spell_button
),!is_checking
);
176 gtk_widget_set_sensitive(GTK_WIDGET(ignore_button
),is_checking
);
177 gtk_widget_set_sensitive(GTK_WIDGET(ignore_all_button
),is_checking
);
181 static void button_spell_callback (GtkWidget
*button
, gpointer data
)
183 GtkTextIter start
,end
;
187 gtk_text_buffer_get_start_iter(textbuffer_main
,&start
);
188 gtk_text_buffer_get_end_iter(textbuffer_main
,&end
);
190 gchar
*buffer
= gtk_text_buffer_get_text(textbuffer_main
,&start
,&end
,FALSE
);
191 //int len = g_utf8_strlen(buffer,-1);
193 vspell
.check(buffer
);
195 if (!word_boundaries
)
196 gtk_text_buffer_set_text (textbuffer_main
, vspell
.get_utf8_text().c_str(),strlen(vspell
.get_utf8_text().c_str()));
200 static void button_ignore_all_callback(GtkWidget
*button
,gpointer data
)
206 static void button_spell_accept_callback (GtkWidget
*button
, gpointer data
)
211 static void spell_entry_activate_callback(GtkEntry
*entry
, gpointer data
)
213 button_spell_accept_callback(NULL
,NULL
);
216 static void button_ignore_callback (GtkWidget
*button
, gpointer data
)
221 static void button_exit_callback (GtkWidget
*button
, gpointer data
)
226 static void window_destroy_callback (GtkObject
*object
,
232 static void button_search_callback(GtkWidget
*button
, gpointer data
);
235 candidates_row_activated (GtkTreeView
*treeview
,
237 GtkTreeViewColumn
*arg2
,
242 if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(list_store
),&iter
,path
))
244 gtk_tree_model_get(GTK_TREE_MODEL(list_store
),&iter
,0,&s
,-1);
245 gtk_entry_set_text(GTK_ENTRY(spell_entry
),s
);
248 void strict_spelling_checking_cb(GtkToggleButton
*b
,VSpell
*vspell
)
250 bool state
= gtk_toggle_button_get_active(b
);
251 vspell
->set_strict_word_checking(state
);
252 //gtk_toggle_button_set_active(b,state);
255 void penalty_modification_cb(GtkEntry
*b
,VSpell
*vspell
)
257 const char *s
= gtk_entry_get_text(b
);
259 if (sscanf(s
,"%f",&val
) == 1)
260 vspell
->set_penalty(val
);
263 void penalty2_modification_cb(GtkEntry
*b
,VSpell
*vspell
)
265 const char *s
= gtk_entry_get_text(b
);
267 if (sscanf(s
,"%f",&val
) == 1)
268 vspell
->set_penalty2(val
);
271 void trigram_cb(GtkToggleButton
*b
,VSpell
*vspell
)
273 bool state
= gtk_toggle_button_get_active(b
);
274 vspell
->set_trigram(state
);
275 //gtk_toggle_button_set_active(b,state);
278 void word_boundaries_cb(GtkToggleButton
*b
,VSpell
*vspell
)
280 word_boundaries
= gtk_toggle_button_get_active(b
);
281 //gtk_toggle_button_set_active(b,state);
284 int main(int argc
,char **argv
)
287 gtk_init(&argc
,&argv
);
288 vspell
.set_penalty(0);
289 vspell
.set_penalty2(1);
290 vspell
.set_trigram(true);
291 word_boundaries
= true;
293 GtkWidget
*window_main
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
294 gtk_container_set_border_width(GTK_CONTAINER(window_main
),10);
295 gtk_window_set_default_size(GTK_WINDOW(window_main
),400,200);
296 g_signal_connect(window_main
,"destroy",G_CALLBACK(window_destroy_callback
),NULL
);
298 GtkWidget
*notebook
= gtk_notebook_new();
299 GtkWidget
*page1
,*page2
;
300 gtk_container_add(GTK_CONTAINER(window_main
),notebook
);
302 GtkWidget
*vbox_main
= gtk_vbox_new(FALSE
,10);
304 gtk_container_set_border_width(GTK_CONTAINER(page1
),10);
305 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
),page1
,gtk_label_new("Main"));
309 GtkWidget *hbox_search = gtk_hbox_new(FALSE,10);
310 gtk_box_pack_start(GTK_BOX(vbox_main),hbox_search,FALSE,TRUE,0);
312 GtkWidget *entry_search = gtk_entry_new();
313 gtk_box_pack_start(GTK_BOX(hbox_search),entry_search,TRUE,TRUE,0);
314 GtkWidget *button_search = gtk_button_new_with_mnemonic("_Search");
315 g_signal_connect(button_search,"clicked",
316 G_CALLBACK(button_search_callback),entry_search);
317 gtk_box_pack_start(GTK_BOX(hbox_search),button_search,FALSE,TRUE,0);
319 log_main = gtk_label_new("");
320 gtk_label_set_line_wrap(GTK_LABEL(log_main),true);
321 gtk_box_pack_start(GTK_BOX(vbox_main),log_main,FALSE,FALSE,0);
324 // Text box+Spell box
325 GtkWidget
*paned
= gtk_hpaned_new();
326 gtk_paned_set_position(GTK_PANED(paned
),300);
327 gtk_box_pack_start(GTK_BOX(vbox_main
),paned
,TRUE
,TRUE
,0);
330 GtkWidget
*scrolled_window
= gtk_scrolled_window_new(NULL
,NULL
);
331 gtk_paned_add1(GTK_PANED(paned
),scrolled_window
);
333 tagtable_main
= gtk_text_tag_table_new();
334 textbuffer_main
= gtk_text_buffer_new(tagtable_main
);
335 gtk_text_buffer_create_tag (textbuffer_main
, "mispelled",
336 "weight", PANGO_WEIGHT_BOLD
,
337 "style", PANGO_STYLE_ITALIC
,
340 gtk_text_buffer_create_tag (textbuffer_main
, "mispelled2",
341 "weight", PANGO_WEIGHT_BOLD
,
342 "style", PANGO_STYLE_ITALIC
,
344 gtk_text_buffer_create_tag (textbuffer_main
, "word",
345 "underline", (gboolean
)TRUE
,
347 gtk_text_buffer_create_tag (textbuffer_main
, "bg-word",
348 "background", "grey",
350 gtk_text_buffer_create_tag (textbuffer_main
, "bg-syllable",
351 "background", "lightgrey",
354 textview_main
= gtk_text_view_new_with_buffer(textbuffer_main
);
355 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview_main
),GTK_WRAP_WORD
);
356 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window
),textview_main
);
359 GtkWidget
*spell_vbox
= gtk_vbox_new(FALSE
,10);
360 gtk_paned_add2(GTK_PANED(paned
),spell_vbox
);
362 GtkWidget
*spell_entry_hbox
= gtk_hbox_new(FALSE
,5);
363 gtk_box_pack_start(GTK_BOX(spell_vbox
),spell_entry_hbox
,FALSE
,FALSE
,0);
365 spell_entry
= gtk_entry_new();
366 g_signal_connect(G_OBJECT(spell_entry
),"activate",G_CALLBACK(spell_entry_activate_callback
),NULL
);
367 gtk_box_pack_start(GTK_BOX(spell_entry_hbox
),spell_entry
,TRUE
,TRUE
,0);
369 GtkWidget
*spell_entry_button
= gtk_button_new();
370 GtkWidget
*spell_entry_button_image
= gtk_image_new_from_stock(GTK_STOCK_OK
,GTK_ICON_SIZE_BUTTON
);
371 g_signal_connect(spell_entry_button
,"clicked",G_CALLBACK(button_spell_accept_callback
),NULL
);
372 gtk_container_add(GTK_CONTAINER(spell_entry_button
),spell_entry_button_image
);
373 gtk_box_pack_start(GTK_BOX(spell_entry_hbox
),spell_entry_button
,FALSE
,FALSE
,0);
375 GtkWidget
*view
= gtk_scrolled_window_new(NULL
,NULL
);
376 gtk_box_pack_start(GTK_BOX(spell_vbox
),view
,TRUE
,TRUE
,0);
378 GtkWidget
*w
= gtk_tree_view_new();
379 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(view
),w
);
380 list_store
= gtk_list_store_new(1,G_TYPE_STRING
);
381 gtk_tree_view_set_model(GTK_TREE_VIEW(w
),GTK_TREE_MODEL(list_store
));
382 gtk_tree_view_append_column(GTK_TREE_VIEW(w
),
383 gtk_tree_view_column_new_with_attributes("Candidates",
384 gtk_cell_renderer_text_new(),
388 g_signal_connect(G_OBJECT(w
),"row-activated",
389 G_CALLBACK(candidates_row_activated
),
393 GtkWidget
*hbox_command
= gtk_hbox_new(TRUE
,10);
394 gtk_box_pack_start(GTK_BOX(vbox_main
),hbox_command
,FALSE
,TRUE
,0);
396 open_button
= gtk_button_new_with_mnemonic("_Open");
397 //g_signal_connect(button_spell,"clicked",G_CALLBACK(button_spell_callback),NULL);
398 gtk_box_pack_start(GTK_BOX(hbox_command
),open_button
,FALSE
,TRUE
,0);
399 spell_button
= gtk_button_new_with_mnemonic("_Check");
400 g_signal_connect(spell_button
,"clicked",G_CALLBACK(button_spell_callback
),NULL
);
401 gtk_box_pack_start(GTK_BOX(hbox_command
),spell_button
,FALSE
,TRUE
,0);
402 //GtkWidget *button_reset = gtk_button_new_with_mnemonic("_Reset");
403 //g_signal_connect(button_reset,"clicked",G_CALLBACK(button_reset_callback),NULL);
404 //gtk_box_pack_start(GTK_BOX(hbox_command),button_reset,FALSE,TRUE,0);
405 ignore_button
= gtk_button_new_with_mnemonic("_Ignore");
406 g_signal_connect(ignore_button
,"clicked",G_CALLBACK(button_ignore_callback
),NULL
);
407 gtk_box_pack_start(GTK_BOX(hbox_command
),ignore_button
,FALSE
,TRUE
,0);
408 ignore_all_button
= gtk_button_new_with_mnemonic("Ignore _All");
409 g_signal_connect(ignore_all_button
,"clicked",G_CALLBACK(button_ignore_all_callback
),NULL
);
410 gtk_box_pack_start(GTK_BOX(hbox_command
),ignore_all_button
,FALSE
,TRUE
,0);
411 GtkWidget
*button_exit
= gtk_button_new_with_mnemonic("_Exit");
412 g_signal_connect(button_exit
,"clicked",G_CALLBACK(button_exit_callback
),NULL
);
413 gtk_box_pack_start(GTK_BOX(hbox_command
),button_exit
,FALSE
,TRUE
,0);
415 vbox_main
= gtk_vbox_new(FALSE
,10);
417 gtk_container_set_border_width(GTK_CONTAINER(page2
),10);
418 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
),page2
,gtk_label_new("Settings"));
419 w
= gtk_check_button_new_with_label("Strict spelling checking");
420 gtk_box_pack_start(GTK_BOX(vbox_main
),w
,FALSE
,FALSE
,0);
421 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w
),vspell
.get_strict_word_checking());
422 g_signal_connect(G_OBJECT(w
),"toggled",G_CALLBACK(strict_spelling_checking_cb
),&vspell
);
424 w
= gtk_check_button_new_with_label("Trigram");
425 gtk_box_pack_start(GTK_BOX(vbox_main
),w
,FALSE
,FALSE
,0);
426 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w
),vspell
.get_trigram());
427 g_signal_connect(G_OBJECT(w
),"toggled",G_CALLBACK(trigram_cb
),&vspell
);
429 w
= gtk_check_button_new_with_label("Show word boundaries");
430 gtk_box_pack_start(GTK_BOX(vbox_main
),w
,FALSE
,FALSE
,0);
431 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w
),word_boundaries
);
432 g_signal_connect(G_OBJECT(w
),"toggled",G_CALLBACK(word_boundaries_cb
),&vspell
);
434 GtkWidget
*hbox
= gtk_hbox_new(FALSE
,10);
435 gtk_box_pack_start(GTK_BOX(vbox_main
),hbox
,FALSE
,FALSE
,0);
436 gtk_box_pack_start(GTK_BOX(hbox
),gtk_label_new("Penalty"),FALSE
,FALSE
,0);
438 gtk_box_pack_start(GTK_BOX(hbox
),w
,FALSE
,FALSE
,0);
440 sprintf(buff
,"%f",vspell
.get_penalty());
441 gtk_entry_set_text(GTK_ENTRY(w
),buff
);
442 g_signal_connect(G_OBJECT(w
),"changed",G_CALLBACK(penalty_modification_cb
),&vspell
);
444 hbox
= gtk_hbox_new(FALSE
,10);
445 gtk_box_pack_start(GTK_BOX(vbox_main
),hbox
,FALSE
,FALSE
,0);
446 gtk_box_pack_start(GTK_BOX(hbox
),gtk_label_new("Penalty2"),FALSE
,FALSE
,0);
448 gtk_box_pack_start(GTK_BOX(hbox
),w
,FALSE
,FALSE
,0);
449 sprintf(buff
,"%f",vspell
.get_penalty2());
450 gtk_entry_set_text(GTK_ENTRY(w
),buff
);
451 g_signal_connect(G_OBJECT(w
),"changed",G_CALLBACK(penalty2_modification_cb
),&vspell
);
455 gtk_widget_show_all(window_main
);
459 void button_search_callback(GtkWidget
*button
, gpointer data
)
461 GtkWidget
*entry_search
= GTK_WIDGET(data
);
462 const char *text
= gtk_entry_get_text(GTK_ENTRY(data
));
464 string
is(viet_to_viscii(text
));
468 while (p
< is
.size()) {
469 int pp
= is
.find(' ',p
);
470 if (pp
== string::npos
)
472 s
= is
.substr(p
,pp
-p
);
474 strid id
= get_ngram()[s
];
475 if (!get_ngram().in_dict(id
)) {
476 char *str
= g_strdup_printf("%s not found",viet_to_utf8(s
.c_str()));
477 gtk_label_set_text(GTK_LABEL(log_main
),str
);
486 ptr = get_root()->follow_syllables(ids);
488 char *str = g_strdup_printf("Word %s found with prob %.02f.",text,ptr->get_prob());
489 gtk_label_set_text(GTK_LABEL(log_main),str);
492 gtk_label_set_text(GTK_LABEL(log_main),"Word not found.");
496 void candidates_reset()
498 gtk_list_store_clear(list_store
);
501 void candidates_add(const gchar
*s
)
504 gtk_list_store_append(list_store
,&iter
);
505 gtk_list_store_set(list_store
,&iter
,
510 bool MyText::ui_syllable_check()
512 unsigned i
,n
= suggestions
.size();
513 for (i
= 0;i
< n
;i
++) {
514 show_wrong_syllables(i
);
517 from
= st
[suggestions
[i
].id
].start
;
518 len
= strlen(get_ngram()[st
[suggestions
[i
].id
].id
]);
519 string s
= substr(from
,len
);
520 gtk_entry_set_text(GTK_ENTRY(spell_entry
),s
.c_str());
521 vector
<string
> candidates
;
524 get_syllable_candidates(get_ngram()[st
[suggestions
[i
].id
].id
],c
);
525 c
.get_list(candidates
);
526 vector
<string
>::iterator iter
;
527 for (iter
= candidates
.begin();iter
!= candidates
.end();++ iter
)
528 candidates_add(viet_to_utf8(iter
->c_str()));
529 processed
= ignore_all
= ignore
= false;
530 while (!gtk_main_iteration() && !ignore
&& !ignore_all
&& !processed
);
536 return true; // force to exit
539 cerr
<< "Input: The right one is:" << endl
;
541 const gchar
*s
= gtk_entry_get_text(GTK_ENTRY(spell_entry
));
544 continue; // i don't accept an empty string
546 replace(st
[suggestions
[i
].id
].start
, // from
547 strlen(get_ngram()[st
[suggestions
[i
].id
].get_id()]), // size
549 vspell
->add(get_ngram()[viet_to_viscii_force(s
)]);
553 return true; // some things went wrong
558 string
MyText::word_to_utf8(unsigned seg_id
)
562 seg
[seg_id
].node
->get_syllables(sylls
);
563 int i
,n
= sylls
.size();
564 for (i
= 0;i
< n
;i
++) {
568 syll
.parse(get_ngram()[sylls
[i
]]);
569 s
+= viet_to_utf8(syll
.to_str().c_str());
574 bool MyText::ui_word_check()
576 unsigned i
,n
= suggestions
.size();
579 for (i
= 0;i
< n
;i
++) {
582 count
= seg
[suggestions
[i
].id
].node
->get_syllable_count();
583 pos
= (*seg
.we
)[seg
[suggestions
[i
].id
].id
].pos
;
586 from
= st
[pos
].start
;
587 len
= st
[pos2
].start
+strlen(get_ngram()[st
[pos2
].id
])-from
;
588 string s
= substr(from
,len
);
589 gtk_entry_set_text(GTK_ENTRY(spell_entry
),s
.c_str());
591 candidates_add(word_to_utf8(suggestions
[i
].id
).c_str());
592 processed
= ignore_all
= ignore
= false;
593 while (!gtk_main_iteration() && !ignore
&& !ignore_all
&& !processed
);
599 return true; // force to exit
602 string s
= gtk_entry_get_text(GTK_ENTRY(spell_entry
));
607 count
= seg
[suggestions
[i
].id
].node
->get_syllable_count();
608 pos
= (*seg
.we
)[seg
[suggestions
[i
].id
].id
].pos
;
612 vector
<unsigned> separators
;
613 while ((p
= s
.find('|')) != string::npos
) {
614 separators
.push_back(st
[pos
].start
+g_utf8_strlen(s
.substr(0,p
).c_str(),-1)+offset
);
618 replace(st
[pos
].start
, // from
619 st
[pos2
].start
+strlen(get_ngram()[st
[pos2
].get_id()])-st
[pos
].start
, // size
622 // add separators after replacing the text, to have old separators removed
623 vspell
->add_word(viet_to_viscii_force(s
.c_str()));
624 vspell
->add_separators(separators
);
625 return false; // continue checking
627 return true; // some things went wrong
632 bool MyText::word_check()
634 bool ret
= Text::word_check();