Added lattice2dot utility
[vspell.git] / ui / gtk / main.cpp
blobd359ddce370940784a9787946f130c243b80260d
1 #include <gtk/gtk.h> // -*- tab-width:2 coding: viscii mode: c++ -*-
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <iostream>
6 #include <sstream>
7 #include "config.h"
8 #include <spell.h>
9 #include <vspell.h>
10 #include <syllable.h>
12 using namespace std;
14 class MyText : public Text
16 public:
17 MyText(VSpell* vs):Text(vs) {}
19 bool word_check();
21 protected:
22 virtual bool ui_syllable_check();
23 virtual bool ui_word_check();
25 void show_wrong_syllables(unsigned p);
26 void show_words();
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
35 public:
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;
73 iter_at(start,0);
74 iter_at(end,length);
75 gtk_text_buffer_apply_tag_by_name(textbuffer_main,
76 "bg-syllable", &start, &end);
77 for (i = 0;i < n;i ++) {
78 int id = sugg[i].id;
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);
83 iter_at(start,from);
84 iter_at(end,from+len);
85 gtk_text_buffer_apply_tag_by_name (textbuffer_main,
86 (i == p ? "mispelled" : "mispelled2"),
87 &start,&end);
91 void MyText::show_words()
93 int n,cc,i,nn;
94 GtkTextIter start,end;
96 n = seg.size();
97 cc = 0;
98 for (i = 0;i < n;i ++) {
99 nn = seg[i].node.node->get_syllable_count();
100 if (nn == 1 && !word_boundaries) {
101 cc += nn;
102 continue;
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);
107 iter_at(start,from);
108 iter_at(end,to);
109 gtk_text_buffer_apply_tag_by_name (textbuffer_main, "word",
110 &start,&end);
111 cc += nn;
115 void MyText::show_wrong_words(unsigned p)
117 int n,cc,nn,i,ii;
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()));
124 iter_at(start,0);
125 iter_at(end,length);
126 gtk_text_buffer_apply_tag_by_name(textbuffer_main,
127 "bg-word", &start, &end);
129 show_words();
130 n = sugg.size();
131 for (i = 0;i < n;i ++) {
132 int id = sugg[i].id;
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);
141 iter_at(start,from);
142 iter_at(end,to);
143 gtk_text_buffer_apply_tag_by_name (textbuffer_main,
144 (i == p ? "mispelled" : "mispelled2"),
145 &start,&end);
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)
164 return;
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);
178 ignore = true;
181 static void button_spell_callback (GtkWidget *button, gpointer data)
183 GtkTextIter start,end;
185 set_state(true);
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);
194 set_state(false);
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)
202 //set_state(false);
203 ignore_all = true;
206 static void button_spell_accept_callback (GtkWidget *button, gpointer data)
208 processed = true;
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)
218 ignore = true;
221 static void button_exit_callback (GtkWidget *button, gpointer data)
223 exit(0);
226 static void window_destroy_callback (GtkObject *object,
227 gpointer user_data)
229 exit(0);
232 static void button_search_callback(GtkWidget *button, gpointer data);
234 static void
235 candidates_row_activated (GtkTreeView *treeview,
236 GtkTreePath *path,
237 GtkTreeViewColumn *arg2,
238 gpointer user_data)
240 GtkTreeIter iter;
241 const char *s;
242 if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(list_store),&iter,path))
243 return;
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);
258 float val;
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);
266 float val;
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)
286 vspell.init();
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);
303 page1 = vbox_main;
304 gtk_container_set_border_width(GTK_CONTAINER(page1),10);
305 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),page1,gtk_label_new("Main"));
308 // Search box
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);
329 // --textbox
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,
338 "foreground", "red",
339 NULL);
340 gtk_text_buffer_create_tag (textbuffer_main, "mispelled2",
341 "weight", PANGO_WEIGHT_BOLD,
342 "style", PANGO_STYLE_ITALIC,
343 NULL);
344 gtk_text_buffer_create_tag (textbuffer_main, "word",
345 "underline", (gboolean)TRUE,
346 NULL);
347 gtk_text_buffer_create_tag (textbuffer_main, "bg-word",
348 "background", "grey",
349 NULL);
350 gtk_text_buffer_create_tag (textbuffer_main, "bg-syllable",
351 "background", "lightgrey",
352 NULL);
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);
358 // --spellbox
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(),
385 "text",
387 NULL));
388 g_signal_connect(G_OBJECT(w),"row-activated",
389 G_CALLBACK(candidates_row_activated),
390 NULL);
392 // Commands
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);
416 page2 = vbox_main;
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);
437 w = gtk_entry_new();
438 gtk_box_pack_start(GTK_BOX(hbox),w,FALSE,FALSE,0);
439 char buff[100];
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);
447 w = gtk_entry_new();
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);
453 set_state(false);
455 gtk_widget_show_all(window_main);
456 gtk_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));
465 int p = 0;
466 string s;
467 vector<strid> ids;
468 while (p < is.size()) {
469 int pp = is.find(' ',p);
470 if (pp == string::npos)
471 pp = is.size();
472 s = is.substr(p,pp-p);
473 p = pp+1;
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);
478 g_free(str);
479 return;
481 ids.push_back(id);
485 WordNodePtr ptr;
486 ptr = get_root()->follow_syllables(ids);
487 if (ptr) {
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);
490 g_free(str);
491 } else
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)
503 GtkTreeIter iter;
504 gtk_list_store_append(list_store,&iter);
505 gtk_list_store_set(list_store,&iter,
506 0,s,
507 -1);
510 bool MyText::ui_syllable_check()
512 unsigned i,n = suggestions.size();
513 for (i = 0;i < n;i ++) {
514 show_wrong_syllables(i);
515 // query
516 int from,len;
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;
522 Candidates c;
523 candidates_reset();
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);
532 if (ignore)
533 continue;
535 if (ignore_all)
536 return true; // force to exit
538 if (processed) {
539 cerr << "Input: The right one is:" << endl;
541 const gchar *s = gtk_entry_get_text(GTK_ENTRY(spell_entry));
543 if (*s == 0)
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
548 s); // text
549 vspell->add(get_ngram()[viet_to_viscii_force(s)]);
551 return false;
553 return true; // some things went wrong
555 return !is_checking;
558 string MyText::word_to_utf8(unsigned seg_id)
560 vector<strid> sylls;
561 string s;
562 seg[seg_id].node->get_syllables(sylls);
563 int i,n = sylls.size();
564 for (i = 0;i < n;i ++) {
565 if (i)
566 s += " ";
567 Syllable syll;
568 syll.parse(get_ngram()[sylls[i]]);
569 s += viet_to_utf8(syll.to_str().c_str());
571 return s;
574 bool MyText::ui_word_check()
576 unsigned i,n = suggestions.size();
577 int pos,pos2,count;
579 for (i = 0;i < n;i ++) {
580 show_wrong_words(i);
581 // query
582 count = seg[suggestions[i].id].node->get_syllable_count();
583 pos = (*seg.we)[seg[suggestions[i].id].id].pos;
584 pos2 = pos+count-1;
585 int from,len;
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());
590 candidates_reset();
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);
595 if (ignore)
596 continue;
598 if (ignore_all)
599 return true; // force to exit
601 if (processed) {
602 string s = gtk_entry_get_text(GTK_ENTRY(spell_entry));
604 if (s.empty())
605 continue;
607 count = seg[suggestions[i].id].node->get_syllable_count();
608 pos = (*seg.we)[seg[suggestions[i].id].id].pos;
609 pos2 = pos+count-1;
611 string::size_type p;
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);
615 s.erase(p,1);
618 replace(st[pos].start, // from
619 st[pos2].start+strlen(get_ngram()[st[pos2].get_id()])-st[pos].start, // size
620 s.c_str()); // text
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
629 return !is_checking;
632 bool MyText::word_check()
634 bool ret = Text::word_check();
635 if (word_boundaries)
636 show_words();
637 return ret;