Allow fix word errors in gtk
[vspell.git] / ui / gtk / main.cpp
blob3b46d842f4e0b13d6583f96949ce530227105107
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 <sstream>
6 #include "config.h"
7 #include <spell.h>
8 #include <vspell.h>
10 using namespace std;
12 class MyText : public Text
14 public:
15 MyText(VSpell* vs):Text(vs) {}
17 protected:
18 virtual bool ui_syllable_check();
19 virtual bool ui_word_check();
21 void show_wrong_syllables(unsigned p);
22 void show_words();
23 void show_wrong_words(unsigned p);
25 void iter_at(GtkTextIter &iter,int pos);
28 class MyTextFactory : public TextFactory
30 public:
31 Text* create(VSpell *vs) const {
32 return new MyText(vs);
36 static GtkTextTagTable *tagtable_main;
37 static GtkTextBuffer *textbuffer_main;
38 static GtkWidget *textview_main;
39 static GtkWidget *log_main;
40 static GtkWidget *spell_entry;
41 static GtkWidget *ignore_button,*ignore_all_button,*spell_button,*open_button;
42 static MyTextFactory myfactory;
43 static VSpell vspell(myfactory);
45 static void text_reset(GtkTextBuffer *textbuffer_main)
47 GtkTextIter start,end;
48 gtk_text_buffer_get_start_iter(textbuffer_main,&start);
49 gtk_text_buffer_get_end_iter(textbuffer_main,&end);
50 gtk_text_buffer_remove_all_tags (textbuffer_main, &start,&end);
53 void MyText::iter_at(GtkTextIter &iter,int pos)
55 gtk_text_buffer_get_iter_at_offset(textbuffer_main,&iter,offset+pos);
58 void MyText::show_wrong_syllables(unsigned p)
60 Suggestions &sugg = suggestions;
61 int cc,ii,nn,i,n = sugg.size();
62 gtk_text_buffer_set_text (textbuffer_main, vspell->get_utf8_text().c_str(),strlen(vspell->get_utf8_text().c_str()));
63 GtkTextIter start,end;
64 for (i = 0;i < n;i ++) {
65 int id = sugg[i].id;
66 int from = st[id].start;
67 int len = strlen(get_sarch()[st[id].id]);
68 printf("Syllable Mispelled: %d (%s) at %d\n",
69 id,get_sarch()[st[id].id],from);
70 iter_at(start,from);
71 iter_at(end,from+len);
72 gtk_text_buffer_apply_tag_by_name (textbuffer_main, (i == p ? "mispelled" : "mispelled2"),
73 &start,&end);
77 void MyText::show_words()
79 int n,cc,i,nn;
80 GtkTextIter start,end;
82 n = seg.size();
83 cc = 0;
84 for (i = 0;i < n;i ++) {
85 nn = seg[i].node.node->get_syllable_count();
86 if (nn == 1) {
87 cc += nn;
88 continue;
90 int from = st[cc].start;
91 int to = st[cc+nn-1].start+strlen(get_sarch()[st[cc+nn-1].id]);
92 printf("From %d to %d(%d)\n",from,to,n);
93 iter_at(start,from);
94 iter_at(end,to);
95 gtk_text_buffer_apply_tag_by_name (textbuffer_main, "word",
96 &start,&end);
97 cc += nn;
101 void MyText::show_wrong_words(unsigned p)
103 int n,cc,nn,i,ii;
104 GtkTextIter start,end;
106 Suggestions &sugg = suggestions;
107 gtk_text_buffer_set_text (textbuffer_main, vspell->get_utf8_text().c_str(),strlen(vspell->get_utf8_text().c_str()));
108 show_words();
109 n = sugg.size();
110 for (i = 0;i < n;i ++) {
111 int id = sugg[i].id;
112 for (cc = ii = 0;ii < id;ii ++)
113 cc += seg[ii].node.node->get_syllable_count();
115 nn = seg[id].node.node->get_syllable_count();
117 int from = st[cc].start;
118 int to = st[cc+nn-1].start+strlen(get_sarch()[st[cc+nn-1].id]);
119 printf("Mispelled at %d\n",id);
120 iter_at(start,from);
121 iter_at(end,to);
122 gtk_text_buffer_apply_tag_by_name (textbuffer_main, (i == p ? "mispelled" : "mispelled2"),
123 &start,&end);
127 static void button_reset_callback (GtkWidget *button, gpointer data)
129 text_reset(textbuffer_main);
132 static bool is_checking = true;
133 static bool ignore = false;
134 static bool ignore_all = false;
135 static bool processed = false;
137 static void set_state(bool spellcheck)
139 GtkTextIter start,end;
141 if (spellcheck == is_checking)
142 return;
144 is_checking = spellcheck;
145 gtk_text_buffer_get_start_iter(textbuffer_main,&start);
146 gtk_text_buffer_get_end_iter(textbuffer_main,&end);
147 gtk_text_buffer_remove_all_tags (textbuffer_main, &start,&end);
149 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview_main),!is_checking);
150 gtk_widget_set_sensitive(GTK_WIDGET(open_button),!is_checking);
151 gtk_widget_set_sensitive(GTK_WIDGET(spell_button),!is_checking);
152 gtk_widget_set_sensitive(GTK_WIDGET(ignore_button),is_checking);
153 gtk_widget_set_sensitive(GTK_WIDGET(ignore_all_button),is_checking);
154 ignore = true;
157 static void button_spell_callback (GtkWidget *button, gpointer data)
159 GtkTextIter start,end;
161 set_state(true);
163 gtk_text_buffer_get_start_iter(textbuffer_main,&start);
164 gtk_text_buffer_get_end_iter(textbuffer_main,&end);
166 gchar *buffer = gtk_text_buffer_get_text(textbuffer_main,&start,&end,FALSE);
167 //int len = g_utf8_strlen(buffer,-1);
169 vspell.check(buffer);
170 set_state(false);
171 gtk_text_buffer_set_text (textbuffer_main, vspell.get_utf8_text().c_str(),strlen(vspell.get_utf8_text().c_str()));
175 static void button_ignore_all_callback(GtkWidget *button,gpointer data)
177 //set_state(false);
178 ignore_all = true;
181 static void button_spell_accept_callback (GtkWidget *button, gpointer data)
183 processed = true;
186 static void spell_entry_activate_callback(GtkEntry *entry, gpointer data)
188 button_spell_accept_callback(NULL,NULL);
191 static void button_ignore_callback (GtkWidget *button, gpointer data)
193 ignore = true;
196 static void button_exit_callback (GtkWidget *button, gpointer data)
198 exit(0);
201 static void window_destroy_callback (GtkObject *object,
202 gpointer user_data)
204 exit(0);
207 static void button_search_callback(GtkWidget *button, gpointer data);
209 int main(int argc,char **argv)
211 gtk_init(&argc,&argv);
213 // sarch["<root>"];
215 vspell.init();
217 GtkWidget *window_main = gtk_window_new(GTK_WINDOW_TOPLEVEL);
218 gtk_container_set_border_width(GTK_CONTAINER(window_main),10);
219 gtk_window_set_default_size(GTK_WINDOW(window_main),400,200);
220 g_signal_connect(window_main,"destroy",G_CALLBACK(window_destroy_callback),NULL);
222 GtkWidget *vbox_main = gtk_vbox_new(FALSE,10);
223 gtk_container_add(GTK_CONTAINER(window_main),vbox_main);
225 // Search box
226 GtkWidget *hbox_search = gtk_hbox_new(FALSE,10);
227 gtk_box_pack_start(GTK_BOX(vbox_main),hbox_search,FALSE,TRUE,0);
229 GtkWidget *entry_search = gtk_entry_new();
230 gtk_box_pack_start(GTK_BOX(hbox_search),entry_search,TRUE,TRUE,0);
231 GtkWidget *button_search = gtk_button_new_with_mnemonic("_Search");
232 g_signal_connect(button_search,"clicked",
233 G_CALLBACK(button_search_callback),entry_search);
234 gtk_box_pack_start(GTK_BOX(hbox_search),button_search,FALSE,TRUE,0);
236 log_main = gtk_label_new("");
237 gtk_label_set_line_wrap(GTK_LABEL(log_main),true);
238 gtk_box_pack_start(GTK_BOX(vbox_main),log_main,FALSE,FALSE,0);
240 // Text box+Spell box
241 GtkWidget *paned = gtk_hpaned_new();
242 gtk_paned_set_position(GTK_PANED(paned),300);
243 gtk_box_pack_start(GTK_BOX(vbox_main),paned,TRUE,TRUE,0);
245 // --textbox
246 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL,NULL);
247 gtk_paned_add1(GTK_PANED(paned),scrolled_window);
249 tagtable_main = gtk_text_tag_table_new();
250 textbuffer_main = gtk_text_buffer_new(tagtable_main);
251 gtk_text_buffer_create_tag (textbuffer_main, "mispelled",
252 "weight", PANGO_WEIGHT_BOLD,
253 "style", PANGO_STYLE_ITALIC,
254 "foreground", "red",
255 NULL);
256 gtk_text_buffer_create_tag (textbuffer_main, "mispelled2",
257 "weight", PANGO_WEIGHT_BOLD,
258 "style", PANGO_STYLE_ITALIC,
259 NULL);
260 gtk_text_buffer_create_tag (textbuffer_main, "word",
261 "underline", (gboolean)TRUE,
262 NULL);
264 textview_main = gtk_text_view_new_with_buffer(textbuffer_main);
265 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview_main),GTK_WRAP_WORD);
266 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window),textview_main);
268 // --spellbox
269 GtkWidget *spell_vbox = gtk_vbox_new(FALSE,10);
270 gtk_paned_add2(GTK_PANED(paned),spell_vbox);
272 GtkWidget *spell_entry_hbox = gtk_hbox_new(FALSE,5);
273 gtk_box_pack_start(GTK_BOX(spell_vbox),spell_entry_hbox,FALSE,FALSE,0);
275 spell_entry = gtk_entry_new();
276 g_signal_connect(G_OBJECT(spell_entry),"activate",G_CALLBACK(spell_entry_activate_callback),NULL);
277 gtk_box_pack_start(GTK_BOX(spell_entry_hbox),spell_entry,TRUE,TRUE,0);
279 GtkWidget *spell_entry_button = gtk_button_new();
280 GtkWidget *spell_entry_button_image = gtk_image_new_from_stock(GTK_STOCK_OK,GTK_ICON_SIZE_BUTTON);
281 g_signal_connect(spell_entry_button,"clicked",G_CALLBACK(button_spell_accept_callback),NULL);
282 gtk_container_add(GTK_CONTAINER(spell_entry_button),spell_entry_button_image);
283 gtk_box_pack_start(GTK_BOX(spell_entry_hbox),spell_entry_button,FALSE,FALSE,0);
285 GtkWidget *w = gtk_tree_view_new();
286 gtk_box_pack_start(GTK_BOX(spell_vbox),w,TRUE,TRUE,0);
288 // Commands
289 GtkWidget *hbox_command = gtk_hbox_new(TRUE,10);
290 gtk_box_pack_start(GTK_BOX(vbox_main),hbox_command,FALSE,TRUE,0);
292 open_button = gtk_button_new_with_mnemonic("_Open");
293 //g_signal_connect(button_spell,"clicked",G_CALLBACK(button_spell_callback),NULL);
294 gtk_box_pack_start(GTK_BOX(hbox_command),open_button,FALSE,TRUE,0);
295 spell_button = gtk_button_new_with_mnemonic("_Check");
296 g_signal_connect(spell_button,"clicked",G_CALLBACK(button_spell_callback),NULL);
297 gtk_box_pack_start(GTK_BOX(hbox_command),spell_button,FALSE,TRUE,0);
298 //GtkWidget *button_reset = gtk_button_new_with_mnemonic("_Reset");
299 //g_signal_connect(button_reset,"clicked",G_CALLBACK(button_reset_callback),NULL);
300 //gtk_box_pack_start(GTK_BOX(hbox_command),button_reset,FALSE,TRUE,0);
301 ignore_button = gtk_button_new_with_mnemonic("_Ignore");
302 g_signal_connect(ignore_button,"clicked",G_CALLBACK(button_ignore_callback),NULL);
303 gtk_box_pack_start(GTK_BOX(hbox_command),ignore_button,FALSE,TRUE,0);
304 ignore_all_button = gtk_button_new_with_mnemonic("Ignore _All");
305 g_signal_connect(ignore_all_button,"clicked",G_CALLBACK(button_ignore_all_callback),NULL);
306 gtk_box_pack_start(GTK_BOX(hbox_command),ignore_all_button,FALSE,TRUE,0);
307 GtkWidget *button_exit = gtk_button_new_with_mnemonic("_Exit");
308 g_signal_connect(button_exit,"clicked",G_CALLBACK(button_exit_callback),NULL);
309 gtk_box_pack_start(GTK_BOX(hbox_command),button_exit,FALSE,TRUE,0);
311 set_state(false);
313 gtk_widget_show_all(window_main);
314 gtk_main();
317 void button_search_callback(GtkWidget *button, gpointer data)
319 GtkWidget *entry_search = GTK_WIDGET(data);
320 const char *text = gtk_entry_get_text(GTK_ENTRY(data));
322 string is(viet_to_viscii(text));
323 int p = 0;
324 string s;
325 vector<strid> ids;
326 while (p < is.size()) {
327 int pp = is.find(' ',p);
328 if (pp == string::npos)
329 pp = is.size();
330 s = is.substr(p,pp-p);
331 p = pp+1;
332 strid id = get_sarch()[s];
333 if (!get_sarch().in_dict(id)) {
334 char *str = g_strdup_printf("%s not found",viet_to_utf8(s.c_str()));
335 gtk_label_set_text(GTK_LABEL(log_main),str);
336 g_free(str);
337 return;
339 ids.push_back(id);
342 WordNodePtr ptr;
343 ptr = get_root()->follow_syllables(ids);
344 if (ptr) {
345 char *str = g_strdup_printf("Word %s found with prob %.02f.",text,ptr->get_prob());
346 gtk_label_set_text(GTK_LABEL(log_main),str);
347 g_free(str);
348 } else
349 gtk_label_set_text(GTK_LABEL(log_main),"Word not found.");
352 bool MyText::ui_syllable_check()
354 unsigned i,n = suggestions.size();
355 for (i = 0;i < n;i ++) {
356 show_wrong_syllables(i);
357 // query
358 int from,len;
359 from = st[suggestions[i].id].start;
360 len = strlen(get_sarch()[st[suggestions[i].id].id]);
361 string s = substr(from,len);
362 gtk_entry_set_text(GTK_ENTRY(spell_entry),s.c_str());
363 processed = ignore_all = ignore = false;
364 while (!gtk_main_iteration() && !ignore && !ignore_all && !processed);
366 if (ignore)
367 continue;
369 if (ignore_all)
370 return true; // force to exit
372 if (processed) {
373 cerr << "Input: The right one is:" << endl;
375 const gchar *s = gtk_entry_get_text(GTK_ENTRY(spell_entry));
377 if (*s == 0)
378 continue; // i don't accept an empty string
380 replace(st[suggestions[i].id].start, // from
381 strlen(get_sarch()[st[suggestions[i].id].get_id()]), // size
382 s); // text
383 vspell->add(get_sarch()[viet_to_viscii_force(s)]);
385 return false;
387 return true; // some things went wrong
389 return !is_checking;
392 bool MyText::ui_word_check()
394 unsigned i,n = suggestions.size();
395 int pos,pos2,count;
397 for (i = 0;i < n;i ++) {
398 show_wrong_words(i);
399 // query
400 count = seg[suggestions[i].id].node->get_syllable_count();
401 pos = (*seg.we)[seg[suggestions[i].id].id].pos;
402 pos2 = pos+count-1;
403 int from,len;
404 from = st[pos].start;
405 len = st[pos2].start+strlen(get_sarch()[st[pos2].id])-from;
406 string s = substr(from,len);
407 gtk_entry_set_text(GTK_ENTRY(spell_entry),s.c_str());
408 processed = ignore_all = ignore = false;
409 while (!gtk_main_iteration() && !ignore && !ignore_all && !processed);
411 if (ignore)
412 continue;
414 if (ignore_all)
415 return true; // force to exit
417 if (processed) {
418 string s = gtk_entry_get_text(GTK_ENTRY(spell_entry));
420 if (s.empty())
421 continue;
423 count = seg[suggestions[i].id].node->get_syllable_count();
424 pos = (*seg.we)[seg[suggestions[i].id].id].pos;
425 pos2 = pos+count-1;
427 string::size_type p;
428 vector<unsigned> separators;
429 while ((p = s.find('|')) != string::npos) {
430 separators.push_back(st[pos].start+g_utf8_strlen(s.substr(0,p).c_str(),-1)+offset);
431 s.erase(p,1);
434 replace(st[pos].start, // from
435 st[pos2].start+strlen(get_sarch()[st[pos2].get_id()])-st[pos].start, // size
436 s.c_str()); // text
438 // add separators after replacing the text, to have old separators removed
439 vspell->add_word(viet_to_viscii_force(s.c_str()));
440 vspell->add_separators(separators);
441 return false; // continue checking
443 return true; // some things went wrong
445 return !is_checking;