1 #include <gtk/gtk.h> // -*- tab-width:2 coding: viscii mode: c++ -*-
13 class MyText
: public Text
16 MyText(VSpell
* vs
):Text(vs
) {}
21 virtual bool ui_syllable_check();
22 virtual bool ui_word_check();
24 void show_wrong_syllables(unsigned p
);
26 void show_wrong_words(unsigned p
);
28 void iter_at(GtkTextIter
&iter
,int pos
);
29 string
word_to_utf8(unsigned seg_id
);
32 class MyTextFactory
: public TextFactory
35 Text
* create(VSpell
*vs
) const {
36 return new MyText(vs
);
40 static GtkTextTagTable
*tagtable_main
;
41 static GtkTextBuffer
*textbuffer_main
;
42 static GtkWidget
*textview_main
;
43 static GtkWidget
*log_main
;
44 static GtkWidget
*spell_entry
;
45 static GtkWidget
*ignore_button
,*ignore_all_button
,*spell_button
,*open_button
;
46 static GtkListStore
*list_store
;
47 static MyTextFactory myfactory
;
48 static VSpell
vspell(myfactory
);
49 static bool word_boundaries
;
51 static void text_reset(GtkTextBuffer
*textbuffer_main
)
53 GtkTextIter start
,end
;
54 gtk_text_buffer_get_start_iter(textbuffer_main
,&start
);
55 gtk_text_buffer_get_end_iter(textbuffer_main
,&end
);
56 gtk_text_buffer_remove_all_tags (textbuffer_main
, &start
,&end
);
59 void MyText::iter_at(GtkTextIter
&iter
,int pos
)
61 gtk_text_buffer_get_iter_at_offset(textbuffer_main
,&iter
,offset
+pos
);
64 void MyText::show_wrong_syllables(unsigned p
)
66 Suggestions
&sugg
= suggestions
;
67 int cc
,ii
,nn
,i
,n
= sugg
.size();
68 gtk_text_buffer_set_text (textbuffer_main
,
69 vspell
->get_utf8_text().c_str(),
70 strlen(vspell
->get_utf8_text().c_str()));
71 GtkTextIter start
,end
;
74 gtk_text_buffer_apply_tag_by_name(textbuffer_main
,
75 "bg-syllable", &start
, &end
);
76 for (i
= 0;i
< n
;i
++) {
78 int from
= st
[id
].start
;
79 int len
= strlen(get_sarch()[st
[id
].id
]);
80 printf("Syllable Mispelled: %d (%s) at %d\n",
81 id
,get_sarch()[st
[id
].id
],from
);
83 iter_at(end
,from
+len
);
84 gtk_text_buffer_apply_tag_by_name (textbuffer_main
,
85 (i
== p
? "mispelled" : "mispelled2"),
90 void MyText::show_words()
93 GtkTextIter start
,end
;
97 for (i
= 0;i
< n
;i
++) {
98 nn
= seg
[i
].node
.node
->get_syllable_count();
99 if (nn
== 1 && !word_boundaries
) {
103 int from
= st
[cc
].start
;
104 int to
= st
[cc
+nn
-1].start
+strlen(get_sarch()[st
[cc
+nn
-1].id
]);
105 printf("From %d to %d(%d)\n",from
,to
,n
);
108 gtk_text_buffer_apply_tag_by_name (textbuffer_main
, "word",
114 void MyText::show_wrong_words(unsigned p
)
117 GtkTextIter start
,end
;
119 Suggestions
&sugg
= suggestions
;
120 gtk_text_buffer_set_text (textbuffer_main
,
121 vspell
->get_utf8_text().c_str(),
122 strlen(vspell
->get_utf8_text().c_str()));
125 gtk_text_buffer_apply_tag_by_name(textbuffer_main
,
126 "bg-word", &start
, &end
);
130 for (i
= 0;i
< n
;i
++) {
132 for (cc
= ii
= 0;ii
< id
;ii
++)
133 cc
+= seg
[ii
].node
.node
->get_syllable_count();
135 nn
= seg
[id
].node
.node
->get_syllable_count();
137 int from
= st
[cc
].start
;
138 int to
= st
[cc
+nn
-1].start
+strlen(get_sarch()[st
[cc
+nn
-1].id
]);
139 printf("Mispelled at %d\n",id
);
142 gtk_text_buffer_apply_tag_by_name (textbuffer_main
,
143 (i
== p
? "mispelled" : "mispelled2"),
148 static void button_reset_callback (GtkWidget
*button
, gpointer data
)
150 text_reset(textbuffer_main
);
153 static bool is_checking
= true;
154 static bool ignore
= false;
155 static bool ignore_all
= false;
156 static bool processed
= false;
158 static void set_state(bool spellcheck
)
160 GtkTextIter start
,end
;
162 if (spellcheck
== is_checking
)
165 is_checking
= spellcheck
;
166 if (is_checking
|| !word_boundaries
) {
167 gtk_text_buffer_get_start_iter(textbuffer_main
,&start
);
168 gtk_text_buffer_get_end_iter(textbuffer_main
,&end
);
169 gtk_text_buffer_remove_all_tags (textbuffer_main
, &start
,&end
);
172 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview_main
),!is_checking
);
173 gtk_widget_set_sensitive(GTK_WIDGET(open_button
),!is_checking
);
174 gtk_widget_set_sensitive(GTK_WIDGET(spell_button
),!is_checking
);
175 gtk_widget_set_sensitive(GTK_WIDGET(ignore_button
),is_checking
);
176 gtk_widget_set_sensitive(GTK_WIDGET(ignore_all_button
),is_checking
);
180 static void button_spell_callback (GtkWidget
*button
, gpointer data
)
182 GtkTextIter start
,end
;
186 gtk_text_buffer_get_start_iter(textbuffer_main
,&start
);
187 gtk_text_buffer_get_end_iter(textbuffer_main
,&end
);
189 gchar
*buffer
= gtk_text_buffer_get_text(textbuffer_main
,&start
,&end
,FALSE
);
190 //int len = g_utf8_strlen(buffer,-1);
192 vspell
.check(buffer
);
194 if (!word_boundaries
)
195 gtk_text_buffer_set_text (textbuffer_main
, vspell
.get_utf8_text().c_str(),strlen(vspell
.get_utf8_text().c_str()));
199 static void button_ignore_all_callback(GtkWidget
*button
,gpointer data
)
205 static void button_spell_accept_callback (GtkWidget
*button
, gpointer data
)
210 static void spell_entry_activate_callback(GtkEntry
*entry
, gpointer data
)
212 button_spell_accept_callback(NULL
,NULL
);
215 static void button_ignore_callback (GtkWidget
*button
, gpointer data
)
220 static void button_exit_callback (GtkWidget
*button
, gpointer data
)
225 static void window_destroy_callback (GtkObject
*object
,
231 static void button_search_callback(GtkWidget
*button
, gpointer data
);
234 candidates_row_activated (GtkTreeView
*treeview
,
236 GtkTreeViewColumn
*arg2
,
241 if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(list_store
),&iter
,path
))
243 gtk_tree_model_get(GTK_TREE_MODEL(list_store
),&iter
,0,&s
,-1);
244 gtk_entry_set_text(GTK_ENTRY(spell_entry
),s
);
247 void strict_spelling_checking_cb(GtkToggleButton
*b
,VSpell
*vspell
)
249 bool state
= gtk_toggle_button_get_active(b
);
250 vspell
->set_strict_word_checking(state
);
251 //gtk_toggle_button_set_active(b,state);
254 void length_normalization_cb(GtkToggleButton
*b
,VSpell
*vspell
)
256 bool state
= gtk_toggle_button_get_active(b
);
257 vspell
->set_normalization(state
);
258 //gtk_toggle_button_set_active(b,state);
261 void penalty_modification_cb(GtkEntry
*b
,VSpell
*vspell
)
263 const char *s
= gtk_entry_get_text(b
);
265 if (sscanf(s
,"%f",&val
) == 1)
266 vspell
->set_penalty(val
);
269 void trigram_cb(GtkToggleButton
*b
,VSpell
*vspell
)
271 bool state
= gtk_toggle_button_get_active(b
);
272 vspell
->set_trigram(state
);
273 //gtk_toggle_button_set_active(b,state);
276 void word_boundaries_cb(GtkToggleButton
*b
,VSpell
*vspell
)
278 word_boundaries
= gtk_toggle_button_get_active(b
);
279 //gtk_toggle_button_set_active(b,state);
282 int main(int argc
,char **argv
)
284 gtk_init(&argc
,&argv
);
289 vspell
.set_penalty(0.05);
290 vspell
.set_normalization(true);
291 vspell
.set_trigram(true);
292 word_boundaries
= true;
294 GtkWidget
*window_main
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
295 gtk_container_set_border_width(GTK_CONTAINER(window_main
),10);
296 gtk_window_set_default_size(GTK_WINDOW(window_main
),400,200);
297 g_signal_connect(window_main
,"destroy",G_CALLBACK(window_destroy_callback
),NULL
);
299 GtkWidget
*notebook
= gtk_notebook_new();
300 GtkWidget
*page1
,*page2
;
301 gtk_container_add(GTK_CONTAINER(window_main
),notebook
);
303 GtkWidget
*vbox_main
= gtk_vbox_new(FALSE
,10);
305 gtk_container_set_border_width(GTK_CONTAINER(page1
),10);
306 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
),page1
,gtk_label_new("Main"));
310 GtkWidget *hbox_search = gtk_hbox_new(FALSE,10);
311 gtk_box_pack_start(GTK_BOX(vbox_main),hbox_search,FALSE,TRUE,0);
313 GtkWidget *entry_search = gtk_entry_new();
314 gtk_box_pack_start(GTK_BOX(hbox_search),entry_search,TRUE,TRUE,0);
315 GtkWidget *button_search = gtk_button_new_with_mnemonic("_Search");
316 g_signal_connect(button_search,"clicked",
317 G_CALLBACK(button_search_callback),entry_search);
318 gtk_box_pack_start(GTK_BOX(hbox_search),button_search,FALSE,TRUE,0);
320 log_main = gtk_label_new("");
321 gtk_label_set_line_wrap(GTK_LABEL(log_main),true);
322 gtk_box_pack_start(GTK_BOX(vbox_main),log_main,FALSE,FALSE,0);
325 // Text box+Spell box
326 GtkWidget
*paned
= gtk_hpaned_new();
327 gtk_paned_set_position(GTK_PANED(paned
),300);
328 gtk_box_pack_start(GTK_BOX(vbox_main
),paned
,TRUE
,TRUE
,0);
331 GtkWidget
*scrolled_window
= gtk_scrolled_window_new(NULL
,NULL
);
332 gtk_paned_add1(GTK_PANED(paned
),scrolled_window
);
334 tagtable_main
= gtk_text_tag_table_new();
335 textbuffer_main
= gtk_text_buffer_new(tagtable_main
);
336 gtk_text_buffer_create_tag (textbuffer_main
, "mispelled",
337 "weight", PANGO_WEIGHT_BOLD
,
338 "style", PANGO_STYLE_ITALIC
,
341 gtk_text_buffer_create_tag (textbuffer_main
, "mispelled2",
342 "weight", PANGO_WEIGHT_BOLD
,
343 "style", PANGO_STYLE_ITALIC
,
345 gtk_text_buffer_create_tag (textbuffer_main
, "word",
346 "underline", (gboolean
)TRUE
,
348 gtk_text_buffer_create_tag (textbuffer_main
, "bg-word",
349 "background", "grey",
351 gtk_text_buffer_create_tag (textbuffer_main
, "bg-syllable",
352 "background", "lightgrey",
355 textview_main
= gtk_text_view_new_with_buffer(textbuffer_main
);
356 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview_main
),GTK_WRAP_WORD
);
357 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window
),textview_main
);
360 GtkWidget
*spell_vbox
= gtk_vbox_new(FALSE
,10);
361 gtk_paned_add2(GTK_PANED(paned
),spell_vbox
);
363 GtkWidget
*spell_entry_hbox
= gtk_hbox_new(FALSE
,5);
364 gtk_box_pack_start(GTK_BOX(spell_vbox
),spell_entry_hbox
,FALSE
,FALSE
,0);
366 spell_entry
= gtk_entry_new();
367 g_signal_connect(G_OBJECT(spell_entry
),"activate",G_CALLBACK(spell_entry_activate_callback
),NULL
);
368 gtk_box_pack_start(GTK_BOX(spell_entry_hbox
),spell_entry
,TRUE
,TRUE
,0);
370 GtkWidget
*spell_entry_button
= gtk_button_new();
371 GtkWidget
*spell_entry_button_image
= gtk_image_new_from_stock(GTK_STOCK_OK
,GTK_ICON_SIZE_BUTTON
);
372 g_signal_connect(spell_entry_button
,"clicked",G_CALLBACK(button_spell_accept_callback
),NULL
);
373 gtk_container_add(GTK_CONTAINER(spell_entry_button
),spell_entry_button_image
);
374 gtk_box_pack_start(GTK_BOX(spell_entry_hbox
),spell_entry_button
,FALSE
,FALSE
,0);
376 GtkWidget
*view
= gtk_scrolled_window_new(NULL
,NULL
);
377 gtk_box_pack_start(GTK_BOX(spell_vbox
),view
,TRUE
,TRUE
,0);
379 GtkWidget
*w
= gtk_tree_view_new();
380 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(view
),w
);
381 list_store
= gtk_list_store_new(1,G_TYPE_STRING
);
382 gtk_tree_view_set_model(GTK_TREE_VIEW(w
),GTK_TREE_MODEL(list_store
));
383 gtk_tree_view_append_column(GTK_TREE_VIEW(w
),
384 gtk_tree_view_column_new_with_attributes("Candidates",
385 gtk_cell_renderer_text_new(),
389 g_signal_connect(G_OBJECT(w
),"row-activated",
390 G_CALLBACK(candidates_row_activated
),
394 GtkWidget
*hbox_command
= gtk_hbox_new(TRUE
,10);
395 gtk_box_pack_start(GTK_BOX(vbox_main
),hbox_command
,FALSE
,TRUE
,0);
397 open_button
= gtk_button_new_with_mnemonic("_Open");
398 //g_signal_connect(button_spell,"clicked",G_CALLBACK(button_spell_callback),NULL);
399 gtk_box_pack_start(GTK_BOX(hbox_command
),open_button
,FALSE
,TRUE
,0);
400 spell_button
= gtk_button_new_with_mnemonic("_Check");
401 g_signal_connect(spell_button
,"clicked",G_CALLBACK(button_spell_callback
),NULL
);
402 gtk_box_pack_start(GTK_BOX(hbox_command
),spell_button
,FALSE
,TRUE
,0);
403 //GtkWidget *button_reset = gtk_button_new_with_mnemonic("_Reset");
404 //g_signal_connect(button_reset,"clicked",G_CALLBACK(button_reset_callback),NULL);
405 //gtk_box_pack_start(GTK_BOX(hbox_command),button_reset,FALSE,TRUE,0);
406 ignore_button
= gtk_button_new_with_mnemonic("_Ignore");
407 g_signal_connect(ignore_button
,"clicked",G_CALLBACK(button_ignore_callback
),NULL
);
408 gtk_box_pack_start(GTK_BOX(hbox_command
),ignore_button
,FALSE
,TRUE
,0);
409 ignore_all_button
= gtk_button_new_with_mnemonic("Ignore _All");
410 g_signal_connect(ignore_all_button
,"clicked",G_CALLBACK(button_ignore_all_callback
),NULL
);
411 gtk_box_pack_start(GTK_BOX(hbox_command
),ignore_all_button
,FALSE
,TRUE
,0);
412 GtkWidget
*button_exit
= gtk_button_new_with_mnemonic("_Exit");
413 g_signal_connect(button_exit
,"clicked",G_CALLBACK(button_exit_callback
),NULL
);
414 gtk_box_pack_start(GTK_BOX(hbox_command
),button_exit
,FALSE
,TRUE
,0);
416 vbox_main
= gtk_vbox_new(FALSE
,10);
418 gtk_container_set_border_width(GTK_CONTAINER(page2
),10);
419 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
),page2
,gtk_label_new("Settings"));
420 w
= gtk_check_button_new_with_label("Strict spelling checking");
421 gtk_box_pack_start(GTK_BOX(vbox_main
),w
,FALSE
,FALSE
,0);
422 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w
),vspell
.get_strict_word_checking());
423 g_signal_connect(G_OBJECT(w
),"toggled",G_CALLBACK(strict_spelling_checking_cb
),&vspell
);
425 w
= gtk_check_button_new_with_label("Length normalization");
426 gtk_box_pack_start(GTK_BOX(vbox_main
),w
,FALSE
,FALSE
,0);
427 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w
),vspell
.get_normalization());
428 g_signal_connect(G_OBJECT(w
),"toggled",G_CALLBACK(length_normalization_cb
),&vspell
);
430 w
= gtk_check_button_new_with_label("Trigram");
431 gtk_box_pack_start(GTK_BOX(vbox_main
),w
,FALSE
,FALSE
,0);
432 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w
),vspell
.get_trigram());
433 g_signal_connect(G_OBJECT(w
),"toggled",G_CALLBACK(trigram_cb
),&vspell
);
435 w
= gtk_check_button_new_with_label("Show word boundaries");
436 gtk_box_pack_start(GTK_BOX(vbox_main
),w
,FALSE
,FALSE
,0);
437 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w
),word_boundaries
);
438 g_signal_connect(G_OBJECT(w
),"toggled",G_CALLBACK(word_boundaries_cb
),&vspell
);
440 GtkWidget
*hbox
= gtk_hbox_new(FALSE
,10);
441 gtk_box_pack_start(GTK_BOX(vbox_main
),hbox
,FALSE
,FALSE
,0);
442 gtk_box_pack_start(GTK_BOX(hbox
),gtk_label_new("Penalty modification"),FALSE
,FALSE
,0);
444 gtk_box_pack_start(GTK_BOX(hbox
),w
,FALSE
,FALSE
,0);
446 sprintf(buff
,"%f",vspell
.get_penalty());
447 gtk_entry_set_text(GTK_ENTRY(w
),buff
);
448 g_signal_connect(G_OBJECT(w
),"changed",G_CALLBACK(penalty_modification_cb
),&vspell
);
452 gtk_widget_show_all(window_main
);
456 void button_search_callback(GtkWidget
*button
, gpointer data
)
458 GtkWidget
*entry_search
= GTK_WIDGET(data
);
459 const char *text
= gtk_entry_get_text(GTK_ENTRY(data
));
461 string
is(viet_to_viscii(text
));
465 while (p
< is
.size()) {
466 int pp
= is
.find(' ',p
);
467 if (pp
== string::npos
)
469 s
= is
.substr(p
,pp
-p
);
471 strid id
= get_sarch()[s
];
472 if (!get_sarch().in_dict(id
)) {
473 char *str
= g_strdup_printf("%s not found",viet_to_utf8(s
.c_str()));
474 gtk_label_set_text(GTK_LABEL(log_main
),str
);
483 ptr = get_root()->follow_syllables(ids);
485 char *str = g_strdup_printf("Word %s found with prob %.02f.",text,ptr->get_prob());
486 gtk_label_set_text(GTK_LABEL(log_main),str);
489 gtk_label_set_text(GTK_LABEL(log_main),"Word not found.");
493 void candidates_reset()
495 gtk_list_store_clear(list_store
);
498 void candidates_add(const gchar
*s
)
501 gtk_list_store_append(list_store
,&iter
);
502 gtk_list_store_set(list_store
,&iter
,
507 bool MyText::ui_syllable_check()
509 unsigned i
,n
= suggestions
.size();
510 for (i
= 0;i
< n
;i
++) {
511 show_wrong_syllables(i
);
514 from
= st
[suggestions
[i
].id
].start
;
515 len
= strlen(get_sarch()[st
[suggestions
[i
].id
].id
]);
516 string s
= substr(from
,len
);
517 gtk_entry_set_text(GTK_ENTRY(spell_entry
),s
.c_str());
518 vector
<string
> candidates
;
521 get_syllable_candidates(get_sarch()[st
[suggestions
[i
].id
].id
],c
);
522 c
.get_list(candidates
);
523 vector
<string
>::iterator iter
;
524 for (iter
= candidates
.begin();iter
!= candidates
.end();++ iter
)
525 candidates_add(viet_to_utf8(iter
->c_str()));
526 processed
= ignore_all
= ignore
= false;
527 while (!gtk_main_iteration() && !ignore
&& !ignore_all
&& !processed
);
533 return true; // force to exit
536 cerr
<< "Input: The right one is:" << endl
;
538 const gchar
*s
= gtk_entry_get_text(GTK_ENTRY(spell_entry
));
541 continue; // i don't accept an empty string
543 replace(st
[suggestions
[i
].id
].start
, // from
544 strlen(get_sarch()[st
[suggestions
[i
].id
].get_id()]), // size
546 vspell
->add(get_sarch()[viet_to_viscii_force(s
)]);
550 return true; // some things went wrong
555 string
MyText::word_to_utf8(unsigned seg_id
)
559 seg
[seg_id
].node
->get_syllables(sylls
);
560 int i
,n
= sylls
.size();
561 for (i
= 0;i
< n
;i
++) {
565 syll
.parse(get_sarch()[sylls
[i
]]);
566 s
+= viet_to_utf8(syll
.to_str().c_str());
571 bool MyText::ui_word_check()
573 unsigned i
,n
= suggestions
.size();
576 for (i
= 0;i
< n
;i
++) {
579 count
= seg
[suggestions
[i
].id
].node
->get_syllable_count();
580 pos
= (*seg
.we
)[seg
[suggestions
[i
].id
].id
].pos
;
583 from
= st
[pos
].start
;
584 len
= st
[pos2
].start
+strlen(get_sarch()[st
[pos2
].id
])-from
;
585 string s
= substr(from
,len
);
586 gtk_entry_set_text(GTK_ENTRY(spell_entry
),s
.c_str());
588 candidates_add(word_to_utf8(suggestions
[i
].id
).c_str());
589 processed
= ignore_all
= ignore
= false;
590 while (!gtk_main_iteration() && !ignore
&& !ignore_all
&& !processed
);
596 return true; // force to exit
599 string s
= gtk_entry_get_text(GTK_ENTRY(spell_entry
));
604 count
= seg
[suggestions
[i
].id
].node
->get_syllable_count();
605 pos
= (*seg
.we
)[seg
[suggestions
[i
].id
].id
].pos
;
609 vector
<unsigned> separators
;
610 while ((p
= s
.find('|')) != string::npos
) {
611 separators
.push_back(st
[pos
].start
+g_utf8_strlen(s
.substr(0,p
).c_str(),-1)+offset
);
615 replace(st
[pos
].start
, // from
616 st
[pos2
].start
+strlen(get_sarch()[st
[pos2
].get_id()])-st
[pos
].start
, // size
619 // add separators after replacing the text, to have old separators removed
620 vspell
->add_word(viet_to_viscii_force(s
.c_str()));
621 vspell
->add_separators(separators
);
622 return false; // continue checking
624 return true; // some things went wrong
629 bool MyText::word_check()
631 bool ret
= Text::word_check();