das news
oldstatus
2005-08-11, Nathan Walp
* A lot of this code (especially the config code) was taken directly * or nearly directly from xchat, version 1.4.2 by Peter Zelezny and others. #define SPELLCHECK_PLUGIN_ID "gtk-spellcheck" static int num_words(const char *); static int get_word(char *, int); static char *have_word(char *, int); static void substitute(char **, int, int, const char *); static GtkListStore *model; substitute_words(GaimAccount *account, GaimConversation *conv, char **message, void *data) if (message == NULL || *message == NULL) for (i = 0; i < l; i++) { word = get_word(*message, i); if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) { memset(&val0, 0, sizeof(val0)); memset(&val1, 0, sizeof(val1)); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, 0, &val0); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, 1, &val1); tmp = have_word(*message, word); bad = g_value_get_string(&val0); good = g_value_get_string(&val1); substitute(message, word, strlen(bad), l += num_words(good) - num_words(bad); i += num_words(good) - num_words(bad); } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)); static int buf_get_line(char *ibuf, char **buf, int *position, int len) { int pos = *position, spos = pos; while (ibuf[pos++] != '\n') { static void load_conf() { const char * const defaultconf = "BAD r\nGOOD are\n\n" model = gtk_list_store_new((gint)N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING); buf = g_build_filename(gaim_user_dir(), "dict", NULL); g_file_get_contents(buf, &ibuf, &size, NULL); ibuf = g_strdup(defaultconf); size = strlen(defaultconf); while(buf_get_line(ibuf, &buf, &pnt, size)) { if (!strncasecmp(buf, "BAD ", 4)) strncpy(name, buf + 4, 81); if (!strncasecmp(buf, "GOOD ", 5)) { strncpy(cmd, buf + 5, 255); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, static int num_words(const char *m) { for (pos = 0; pos < strlen(m); pos++) { case 0: /* expecting word */ if (!g_ascii_isspace(m[pos]) && !g_ascii_ispunct(m[pos])) { } else if (m[pos] == '<') case 1: /* inside word */ else if (g_ascii_isspace(m[pos]) || g_ascii_ispunct(m[pos])) case 2: /* inside HTML tag */ static int get_word(char *m, int word) { for (pos = 0; pos < strlen(m) && count <= word; pos++) { if (!g_ascii_isspace(m[pos]) && !g_ascii_ispunct(m[pos])) { } else if (m[pos] == '<') else if (g_ascii_isspace(m[pos]) || g_ascii_ispunct(m[pos])) static char *have_word(char *m, int pos) { char *tmp = strpbrk(&m[pos], "' \t\f\r\n\"><.?!-,/"); int len = (int)(tmp - &m[pos]); strncat(tmp, &m[pos], len); static void substitute(char **mes, int pos, int m, const char *text) { char *new = g_malloc(strlen(*mes) + strlen(text) + 1); strcat(new, &(*mes)[pos + m]); static GtkWidget *bad_entry; static GtkWidget *good_entry; static void on_edited(GtkCellRendererText *cellrenderertext, gchar *path, gchar *arg2, gpointer data) memset(&val, 0, sizeof(val)); g_return_if_fail(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &iter, path)); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, GPOINTER_TO_INT(data), &val); if(strcmp(arg2, g_value_get_string(&val))) { gtk_list_store_set(model, &iter, GPOINTER_TO_INT(data), arg2, -1); static void list_add_new() gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, gtk_entry_get_text(GTK_ENTRY(bad_entry)), 1, gtk_entry_get_text(GTK_ENTRY(good_entry)), gtk_editable_select_region(GTK_EDITABLE(bad_entry), 0, -1); gtk_widget_grab_focus(bad_entry); static void add_selected_row_to_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) GSList **list = (GSList **)data; *list = g_slist_append(*list, gtk_tree_path_copy(path) ); static void remove_row(void *data1, gpointer data2) GtkTreePath *path = (GtkTreePath*)data1; gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path); gtk_list_store_remove(model, &iter); gtk_tree_path_free(path); static void list_delete() sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)); gtk_tree_selection_selected_foreach(sel, add_selected_row_to_list, &list); g_slist_foreach(list, remove_row, NULL); char *name, *tempfilename; name = g_build_filename(gaim_user_dir(), "dict", NULL); tempfilename = g_strdup_printf("%s.XXXXXX", name); fd = g_mkstemp(tempfilename); if (!(f = fdopen(fd, "w"))) { fchmod(fd, S_IRUSR | S_IWUSR); if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) { memset(&val0, 0, sizeof(val0)); memset(&val1, 0, sizeof(val1)); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, 0, &val0); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, 1, &val1); fprintf(f, "BAD %s\nGOOD %s\n\n", g_value_get_string(&val0), g_value_get_string(&val1)); } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)); gaim_debug(GAIM_DEBUG_ERROR, "spellchk", "Error writing to %s: %m\n", tempfilename); g_rename(tempfilename, name); check_if_something_is_selected(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) *((gboolean*)data) = TRUE; static void on_selection_changed(GtkTreeSelection *sel, gtk_tree_selection_selected_foreach(sel, check_if_something_is_selected, &is); gtk_widget_set_sensitive((GtkWidget*)data, is); static gboolean non_empty(const char *s) while(*s && g_ascii_isspace(*s)) static void on_entry_changed(GtkEditable *editable, gpointer data) gtk_widget_set_sensitive((GtkWidget*)data, non_empty(gtk_entry_get_text(GTK_ENTRY(bad_entry))) && non_empty(gtk_entry_get_text(GTK_ENTRY(good_entry)))); plugin_load(GaimPlugin *plugin) void *conv_handle = gaim_conversations_get_handle(); gaim_signal_connect(conv_handle, "writing-im-msg", plugin, GAIM_CALLBACK(substitute_words), NULL); gaim_signal_connect(conv_handle, "writing-chat-msg", plugin, GAIM_CALLBACK(substitute_words), NULL); get_config_frame(GaimPlugin *plugin) GtkWidget *ret, *vbox, *win; GtkCellRenderer *renderer; GtkTreeViewColumn *column; sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); ret = gtk_vbox_new(FALSE, 18); gtk_container_set_border_width (GTK_CONTAINER (ret), 12); vbox = gaim_gtk_make_frame(ret, _("Text Replacements")); gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); gtk_widget_set_size_request(vbox, 300, -1); win = gtk_scrolled_window_new(0, 0); gtk_container_add(GTK_CONTAINER(vbox), win); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(win), gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (win), tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); /* gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE); */ gtk_widget_set_size_request(tree, 260,200); renderer = gtk_cell_renderer_text_new (); g_object_set (G_OBJECT (renderer), g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(on_edited), GINT_TO_POINTER(0)); column = gtk_tree_view_column_new_with_attributes (_("You type"), renderer, "text", BAD_COLUMN, NULL); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width(column, 130); /* gtk_tree_view_column_set_resizable(column, TRUE); */ gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column); renderer = gtk_cell_renderer_text_new (); g_object_set (G_OBJECT (renderer), g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(on_edited), GINT_TO_POINTER(1)); column = gtk_tree_view_column_new_with_attributes (_("You send"), renderer, "text", GOOD_COLUMN, NULL); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width(column, 130); /* gtk_tree_view_column_set_resizable(column, TRUE); */ gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), gtk_container_add(GTK_CONTAINER(win), tree); hbox = gtk_hbutton_box_new(); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); button = gtk_button_new_from_stock(GTK_STOCK_DELETE); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(list_delete), NULL); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); gtk_widget_set_sensitive(button, FALSE); g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))), "changed", G_CALLBACK(on_selection_changed), button); vbox = gaim_gtk_make_frame(ret, _("Add a new text replacement")); gtk_widget_set_size_request(vbox, 300, -1); hbox = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new_with_mnemonic(_("You _type:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); bad_entry = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(bad_entry), 40); gtk_box_pack_start(GTK_BOX(hbox), bad_entry, TRUE, TRUE, 0); gtk_size_group_add_widget(sg, bad_entry); gtk_label_set_mnemonic_widget(GTK_LABEL(label), bad_entry); gtk_widget_show(bad_entry); hbox = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new_with_mnemonic(_("You _send:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); good_entry = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(good_entry), 255); gtk_box_pack_start(GTK_BOX(hbox), good_entry, TRUE, TRUE, 0); gtk_size_group_add_widget(sg, good_entry); gtk_label_set_mnemonic_widget(GTK_LABEL(label), good_entry); gtk_widget_show(good_entry); hbox = gtk_hbutton_box_new(); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); button = gtk_button_new_from_stock(GTK_STOCK_ADD); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(list_add_new), NULL); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(bad_entry), "changed", G_CALLBACK(on_entry_changed), button); g_signal_connect(G_OBJECT(good_entry), "changed", G_CALLBACK(on_entry_changed), button); gtk_widget_set_sensitive(button, FALSE); gtk_widget_show_all(ret); static GaimGtkPluginUiInfo ui_info = static GaimPluginInfo info = N_("Replaces text in outgoing messages according to user-defined rules."), N_("Replaces text in outgoing messages according to user-defined rules."), "Eric Warmenhoven <eric@warmenhoven.org>", init_plugin(GaimPlugin *plugin) GAIM_INIT_PLUGIN(spellcheck, init_plugin, info)