comparison plugins/spellchk.c @ 12711:145f76e74a9f

[gaim-migrate @ 15055] Fix SF Bug #1384698 - "Last word in text auto replace not changed" This uses astro96's idea: 'when the user types something like "Hi how r u" they will see this (where the "^" is the cursor): "Hi how are u^" When they hit enter to send the message, instead of sending the message, the last word would be replaced: [Enter] "Hi how are you^" and then if they hit enter again it would send the message.' I code a preference for this, but have #if 0'ed it before committing. I don't think we need a preference to disable this. If it turns out I'm wrong, the code is right there to use. committer: Tailor Script <tailor@pidgin.im>
author Richard Laager <rlaager@wiktel.com>
date Wed, 04 Jan 2006 03:01:32 +0000
parents 9c2a4e327718
children 5f15d53b610a
comparison
equal deleted inserted replaced
12710:2d326453b33d 12711:145f76e74a9f
38 #include "signals.h" 38 #include "signals.h"
39 #include "util.h" 39 #include "util.h"
40 #include "version.h" 40 #include "version.h"
41 41
42 #include "gtkplugin.h" 42 #include "gtkplugin.h"
43 #include "gtkprefs.h"
43 #include "gtkutils.h" 44 #include "gtkutils.h"
44 45
45 #include <stdio.h> 46 #include <stdio.h>
46 #include <string.h> 47 #include <string.h>
47 #ifndef _WIN32 48 #ifndef _WIN32
67 GtkTextMark *mark_insert_end; 68 GtkTextMark *mark_insert_end;
68 69
69 const gchar *word; 70 const gchar *word;
70 gboolean inserting; 71 gboolean inserting;
71 gboolean ignore_correction; 72 gboolean ignore_correction;
73 gboolean ignore_correction_on_send;
72 gint pos; 74 gint pos;
73 }; 75 };
74 76
75 typedef struct _spellchk spellchk; 77 typedef struct _spellchk spellchk;
76 78
368 } 370 }
369 371
370 return TRUE; 372 return TRUE;
371 } 373 }
372 374
373 static void 375 static gboolean
374 check_range(spellchk *spell, GtkTextBuffer *buffer, 376 check_range(spellchk *spell, GtkTextBuffer *buffer,
375 GtkTextIter start, GtkTextIter end) { 377 GtkTextIter start, GtkTextIter end, gboolean sending)
376 378 {
379 gboolean replaced;
377 gboolean result; 380 gboolean result;
378 gchar *tmp; 381 gchar *tmp;
379 int period_count = 0; 382 int period_count = 0;
380 gchar *word; 383 gchar *word;
381 GtkTextMark *mark; 384 GtkTextMark *mark;
382 GtkTextIter pos; 385 GtkTextIter pos;
383 386
384 if (substitute_simple_buffer(buffer)) 387 if ((replaced = substitute_simple_buffer(buffer)))
385 { 388 {
386 mark = gtk_text_buffer_get_insert(buffer); 389 mark = gtk_text_buffer_get_insert(buffer);
387 gtk_text_buffer_get_iter_at_mark(buffer, &pos, mark); 390 gtk_text_buffer_get_iter_at_mark(buffer, &pos, mark);
388 spell->pos = gtk_text_iter_get_offset(&pos); 391 spell->pos = gtk_text_iter_get_offset(&pos);
389 392
390 gtk_text_buffer_get_iter_at_mark(buffer, &start, mark); 393 gtk_text_buffer_get_iter_at_mark(buffer, &start, mark);
391 gtk_text_buffer_get_iter_at_mark(buffer, &end, mark); 394 gtk_text_buffer_get_iter_at_mark(buffer, &end, mark);
392 } 395 }
393 396
394 /* We need to go backwords to find out if we are inside a word or not. */ 397 if (!sending)
395 gtk_text_iter_backward_char(&end); 398 {
396 399 /* We need to go backwords to find out if we are inside a word or not. */
397 if (spellchk_inside_word(&end)) { 400 gtk_text_iter_backward_char(&end);
398 gtk_text_iter_forward_char(&end); 401
399 return; /* We only pay attention to whole words. */ 402 if (spellchk_inside_word(&end))
403 {
404 gtk_text_iter_forward_char(&end);
405 return replaced; /* We only pay attention to whole words. */
406 }
400 } 407 }
401 408
402 /* We could be in the middle of a whitespace block. Check for that. */ 409 /* We could be in the middle of a whitespace block. Check for that. */
403 result = gtk_text_iter_backward_char(&end); 410 result = gtk_text_iter_backward_char(&end);
404 411
405 if (!spellchk_inside_word(&end)) { 412 if (!spellchk_inside_word(&end))
413 {
406 if (result) 414 if (result)
407 gtk_text_iter_forward_char(&end); 415 gtk_text_iter_forward_char(&end);
408 return; 416 return replaced;
409 } 417 }
410 418
411 if (result) 419 if (result)
412 gtk_text_iter_forward_char(&end); 420 gtk_text_iter_forward_char(&end);
413 421
452 gtk_text_buffer_get_iter_at_mark(buffer, &pos, mark); 460 gtk_text_buffer_get_iter_at_mark(buffer, &pos, mark);
453 spell->pos = gtk_text_iter_get_offset(&pos); 461 spell->pos = gtk_text_iter_get_offset(&pos);
454 462
455 g_free(word); 463 g_free(word);
456 g_free(tmp); 464 g_free(tmp);
457 return; 465 return TRUE;
458 } 466 }
459 g_free(tmp); 467 g_free(tmp);
460 468
461 spell->word = NULL; 469 spell->word = NULL;
462 470
471 return replaced;
463 } 472 }
464 473
465 /* insertion works like this: 474 /* insertion works like this:
466 * - before the text is inserted, we mark the position in the buffer. 475 * - before the text is inserted, we mark the position in the buffer.
467 * - after the text is inserted, we see where our mark is and use that and 476 * - after the text is inserted, we see where our mark is and use that and
487 gchar *text, gint len, spellchk *spell) 496 gchar *text, gint len, spellchk *spell)
488 { 497 {
489 GtkTextIter start, end; 498 GtkTextIter start, end;
490 GtkTextMark *mark; 499 GtkTextMark *mark;
491 500
501 spell->ignore_correction_on_send = FALSE;
502
492 if (spell->ignore_correction) { 503 if (spell->ignore_correction) {
493 spell->ignore_correction = FALSE; 504 spell->ignore_correction = FALSE;
494 return; 505 return;
495 } 506 }
496 507
497 /* we need to check a range of text. */ 508 /* we need to check a range of text. */
498 gtk_text_buffer_get_iter_at_mark(buffer, &start, spell->mark_insert_start); 509 gtk_text_buffer_get_iter_at_mark(buffer, &start, spell->mark_insert_start);
499 510
500 if (len == 1) 511 if (len == 1)
501 check_range(spell, buffer, start, *iter); 512 check_range(spell, buffer, start, *iter, FALSE);
502 513
503 /* if check_range modified the buffer, iter has been invalidated */ 514 /* if check_range modified the buffer, iter has been invalidated */
504 mark = gtk_text_buffer_get_insert(buffer); 515 mark = gtk_text_buffer_get_insert(buffer);
505 gtk_text_buffer_get_iter_at_mark(buffer, &end, mark); 516 gtk_text_buffer_get_iter_at_mark(buffer, &end, mark);
506 gtk_text_buffer_move_mark(buffer, spell->mark_insert_end, &end); 517 gtk_text_buffer_move_mark(buffer, spell->mark_insert_end, &end);
507 518
508 spell->inserting = FALSE; 519 spell->inserting = FALSE;
509
510 } 520 }
511 521
512 static void 522 static void
513 delete_range_after(GtkTextBuffer *buffer, 523 delete_range_after(GtkTextBuffer *buffer,
514 GtkTextIter *start, GtkTextIter *end, spellchk *spell) 524 GtkTextIter *start, GtkTextIter *end, spellchk *spell)
516 GtkTextIter start2, end2; 526 GtkTextIter start2, end2;
517 GtkTextMark *mark; 527 GtkTextMark *mark;
518 GtkTextIter pos; 528 GtkTextIter pos;
519 gint place; 529 gint place;
520 530
531 spell->ignore_correction_on_send = FALSE;
532
521 if (!spell->word) 533 if (!spell->word)
522 return; 534 return;
523 535
524 if (spell->inserting == TRUE) 536 if (spell->inserting == TRUE)
525 return; 537 return;
526
527 538
528 spell->inserting = TRUE; 539 spell->inserting = TRUE;
529 540
530 mark = gtk_text_buffer_get_insert(buffer); 541 mark = gtk_text_buffer_get_insert(buffer);
531 gtk_text_buffer_get_iter_at_mark(buffer, &pos, mark); 542 gtk_text_buffer_get_iter_at_mark(buffer, &pos, mark);
540 gtk_text_buffer_get_iter_at_mark(buffer, &end2, spell->mark_insert_end); 551 gtk_text_buffer_get_iter_at_mark(buffer, &end2, spell->mark_insert_end);
541 552
542 gtk_text_buffer_delete(buffer, &start2, &end2); 553 gtk_text_buffer_delete(buffer, &start2, &end2);
543 gtk_text_buffer_insert(buffer, &start2, spell->word, -1); 554 gtk_text_buffer_insert(buffer, &start2, spell->word, -1);
544 spell->ignore_correction = TRUE; 555 spell->ignore_correction = TRUE;
556 spell->ignore_correction_on_send = TRUE;
545 557
546 spell->inserting = FALSE; 558 spell->inserting = FALSE;
547 spell->word = NULL; 559 spell->word = NULL;
560 }
561
562 static void
563 message_send_cb(GtkWidget *widget, spellchk *spell)
564 {
565 GtkTextBuffer *buffer;
566 GtkTextIter start, end;
567 GtkTextMark *mark;
568 gboolean replaced;
569
570 if (spell->ignore_correction_on_send)
571 {
572 spell->ignore_correction_on_send = FALSE;
573 return;
574 }
575
576 #if 0
577 if (!gaim_prefs_get_bool("/plugins/gtk/spellchk/last_word_replace"))
578 return;
579 #endif
580
581 buffer = gtk_text_view_get_buffer(spell->view);
582
583 gtk_text_buffer_get_end_iter(buffer, &start);
584 gtk_text_buffer_get_end_iter(buffer, &end);
585 spell->inserting = TRUE;
586 replaced = check_range(spell, buffer, start, end, TRUE);
587 spell->inserting = FALSE;
588
589 /* if check_range modified the buffer, iter has been invalidated */
590 mark = gtk_text_buffer_get_insert(buffer);
591 gtk_text_buffer_get_iter_at_mark(buffer, &end, mark);
592 gtk_text_buffer_move_mark(buffer, spell->mark_insert_end, &end);
593
594 if (replaced)
595 {
596 g_signal_stop_emission_by_name(widget, "message_send");
597 spell->ignore_correction_on_send = TRUE;
598 }
548 } 599 }
549 600
550 static void 601 static void
551 spellchk_new_attach(GaimConversation *conv) 602 spellchk_new_attach(GaimConversation *conv)
552 { 603 {
591 G_CALLBACK(insert_text_before), spell); 642 G_CALLBACK(insert_text_before), spell);
592 g_signal_connect_after(G_OBJECT(buffer), 643 g_signal_connect_after(G_OBJECT(buffer),
593 "insert-text", 644 "insert-text",
594 G_CALLBACK(insert_text_after), spell); 645 G_CALLBACK(insert_text_after), spell);
595 646
647 g_signal_connect(G_OBJECT(gtkconv->entry), "message_send",
648 G_CALLBACK(message_send_cb), spell);
596 return; 649 return;
597 } 650 }
598 651
599 static int buf_get_line(char *ibuf, char **buf, int *position, int len) 652 static int buf_get_line(char *ibuf, char **buf, int *position, int len)
600 { 653 {
2041 GtkWidget *button; 2094 GtkWidget *button;
2042 GtkSizeGroup *sg; 2095 GtkSizeGroup *sg;
2043 GtkSizeGroup *sg2; 2096 GtkSizeGroup *sg2;
2044 GtkCellRenderer *renderer; 2097 GtkCellRenderer *renderer;
2045 GtkTreeViewColumn *column; 2098 GtkTreeViewColumn *column;
2046 2099 GtkWidget *vbox2;
2047 ret = gtk_vbox_new(FALSE, 18); 2100 GtkWidget *hbox2;
2048 gtk_container_set_border_width (GTK_CONTAINER(ret), 12); 2101 GtkWidget *vbox3;
2102
2103 ret = gtk_vbox_new(FALSE, GAIM_HIG_CAT_SPACE);
2104 gtk_container_set_border_width (GTK_CONTAINER(ret), GAIM_HIG_BORDER);
2049 2105
2050 vbox = gaim_gtk_make_frame(ret, _("Text Replacements")); 2106 vbox = gaim_gtk_make_frame(ret, _("Text Replacements"));
2051 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); 2107 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
2052 gtk_widget_show(vbox); 2108 gtk_widget_show(vbox);
2053 2109
2136 2192
2137 gtk_widget_show(button); 2193 gtk_widget_show(button);
2138 2194
2139 vbox = gaim_gtk_make_frame(ret, _("Add a new text replacement")); 2195 vbox = gaim_gtk_make_frame(ret, _("Add a new text replacement"));
2140 2196
2197 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
2198 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
2199 gtk_widget_show(hbox);
2200 vbox2 = gtk_vbox_new(FALSE, GAIM_HIG_BOX_SPACE);
2201 gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE, TRUE, 0);
2202 gtk_widget_show(vbox2);
2203
2141 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); 2204 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2142 sg2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); 2205 sg2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2143 2206
2144 hbox = gtk_hbox_new(FALSE, 2); 2207 hbox2 = gtk_hbox_new(FALSE, 2);
2145 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); 2208 gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, 0);
2146 gtk_widget_show(hbox); 2209 gtk_widget_show(hbox2);
2147 2210
2148 label = gtk_label_new_with_mnemonic(_("You _type:")); 2211 label = gtk_label_new_with_mnemonic(_("You _type:"));
2149 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); 2212 gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
2150 gtk_size_group_add_widget(sg, label); 2213 gtk_size_group_add_widget(sg, label);
2151 gtk_misc_set_alignment(GTK_MISC(label), 0, 0); 2214 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
2152 2215
2153 bad_entry = gtk_entry_new(); 2216 bad_entry = gtk_entry_new();
2154 /* Set a minimum size. Since they're in a size group, the other entry will match up. */ 2217 /* Set a minimum size. Since they're in a size group, the other entry will match up. */
2155 gtk_widget_set_size_request(bad_entry, 350, -1); 2218 gtk_widget_set_size_request(bad_entry, 350, -1);
2156 gtk_box_pack_start(GTK_BOX(hbox), bad_entry, TRUE, TRUE, 0); 2219 gtk_box_pack_start(GTK_BOX(hbox2), bad_entry, TRUE, TRUE, 0);
2157 gtk_size_group_add_widget(sg2, bad_entry); 2220 gtk_size_group_add_widget(sg2, bad_entry);
2158 gtk_label_set_mnemonic_widget(GTK_LABEL(label), bad_entry); 2221 gtk_label_set_mnemonic_widget(GTK_LABEL(label), bad_entry);
2159 gtk_widget_show(bad_entry); 2222 gtk_widget_show(bad_entry);
2160 2223
2161 hbox = gtk_hbox_new(FALSE, 2); 2224 hbox2 = gtk_hbox_new(FALSE, 2);
2162 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); 2225 gtk_box_pack_start(GTK_BOX(vbox2), hbox2, FALSE, FALSE, 0);
2163 gtk_widget_show(hbox); 2226 gtk_widget_show(hbox2);
2164 2227
2165 label = gtk_label_new_with_mnemonic(_("You _send:")); 2228 label = gtk_label_new_with_mnemonic(_("You _send:"));
2166 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); 2229 gtk_box_pack_start(GTK_BOX(hbox2), label, FALSE, FALSE, 0);
2167 gtk_size_group_add_widget(sg, label); 2230 gtk_size_group_add_widget(sg, label);
2168 gtk_misc_set_alignment(GTK_MISC(label), 0, 0); 2231 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
2169 2232
2170 good_entry = gtk_entry_new(); 2233 good_entry = gtk_entry_new();
2171 gtk_box_pack_start(GTK_BOX(hbox), good_entry, TRUE, TRUE, 0); 2234 gtk_box_pack_start(GTK_BOX(hbox2), good_entry, TRUE, TRUE, 0);
2172 gtk_size_group_add_widget(sg2, good_entry); 2235 gtk_size_group_add_widget(sg2, good_entry);
2173 gtk_label_set_mnemonic_widget(GTK_LABEL(label), good_entry); 2236 gtk_label_set_mnemonic_widget(GTK_LABEL(label), good_entry);
2174 gtk_widget_show(good_entry); 2237 gtk_widget_show(good_entry);
2175 2238
2176 /* Created here so it can be passed to whole_words_button_toggled. */ 2239 /* Created here so it can be passed to whole_words_button_toggled. */
2179 complete_toggle = gtk_check_button_new_with_mnemonic(_("Only replace _whole words")); 2242 complete_toggle = gtk_check_button_new_with_mnemonic(_("Only replace _whole words"));
2180 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(complete_toggle), TRUE); 2243 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(complete_toggle), TRUE);
2181 g_signal_connect(G_OBJECT(complete_toggle), "clicked", 2244 g_signal_connect(G_OBJECT(complete_toggle), "clicked",
2182 G_CALLBACK(whole_words_button_toggled), case_toggle); 2245 G_CALLBACK(whole_words_button_toggled), case_toggle);
2183 gtk_widget_show(complete_toggle); 2246 gtk_widget_show(complete_toggle);
2184 gtk_box_pack_start(GTK_BOX(vbox), complete_toggle, FALSE, FALSE, 0); 2247 gtk_box_pack_start(GTK_BOX(vbox2), complete_toggle, FALSE, FALSE, 0);
2185 2248
2186 /* The button is created above so it can be passed to whole_words_button_toggled. */ 2249 /* The button is created above so it can be passed to whole_words_button_toggled. */
2187 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(case_toggle), FALSE); 2250 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(case_toggle), FALSE);
2188 gtk_widget_show(case_toggle); 2251 gtk_widget_show(case_toggle);
2189 gtk_box_pack_start(GTK_BOX(vbox), case_toggle, FALSE, FALSE, 0); 2252 gtk_box_pack_start(GTK_BOX(vbox2), case_toggle, FALSE, FALSE, 0);
2190 2253
2191 hbox = gtk_hbutton_box_new();
2192 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2193 button = gtk_button_new_from_stock(GTK_STOCK_ADD); 2254 button = gtk_button_new_from_stock(GTK_STOCK_ADD);
2194 g_signal_connect(G_OBJECT(button), "clicked", 2255 g_signal_connect(G_OBJECT(button), "clicked",
2195 G_CALLBACK(list_add_new), NULL); 2256 G_CALLBACK(list_add_new), NULL);
2196 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); 2257 vbox3 = gtk_vbox_new(FALSE, 0);
2258 gtk_box_pack_start(GTK_BOX(hbox), vbox3, TRUE, FALSE, 0);
2259 gtk_widget_show(vbox3);
2260 gtk_box_pack_end(GTK_BOX(vbox3), button, FALSE, FALSE, 0);
2197 g_signal_connect(G_OBJECT(bad_entry), "changed", G_CALLBACK(on_entry_changed), button); 2261 g_signal_connect(G_OBJECT(bad_entry), "changed", G_CALLBACK(on_entry_changed), button);
2198 g_signal_connect(G_OBJECT(good_entry), "changed", G_CALLBACK(on_entry_changed), button); 2262 g_signal_connect(G_OBJECT(good_entry), "changed", G_CALLBACK(on_entry_changed), button);
2199 gtk_widget_set_sensitive(button, FALSE); 2263 gtk_widget_set_sensitive(button, FALSE);
2200 gtk_widget_show(button); 2264 gtk_widget_show(button);
2201 2265
2266 #if 0
2267 vbox = gaim_gtk_make_frame(ret, _("General Text Replacement Options"));
2268 gaim_gtk_prefs_checkbox(_("Enable replacement of last word on send"),
2269 "/plugins/gtk/spellchk/last_word_replace", vbox);
2270 #endif
2202 2271
2203 gtk_widget_show_all(ret); 2272 gtk_widget_show_all(ret);
2204 return ret; 2273 return ret;
2205 } 2274 }
2206 2275
2237 }; 2306 };
2238 2307
2239 static void 2308 static void
2240 init_plugin(GaimPlugin *plugin) 2309 init_plugin(GaimPlugin *plugin)
2241 { 2310 {
2311 #if 0
2312 gaim_prefs_add_none("/plugins");
2313 gaim_prefs_add_none("/plugins/gtk");
2314 gaim_prefs_add_none("/plugins/gtk/spellchk");
2315 gaim_prefs_add_bool("/plugins/gtk/spellchk/last_word_replace", TRUE);
2316 #endif
2242 } 2317 }
2243 2318
2244 GAIM_INIT_PLUGIN(spellcheck, init_plugin, info) 2319 GAIM_INIT_PLUGIN(spellcheck, init_plugin, info)