📄 spellchk.c
字号:
"BAD youll\nGOOD you'll\n" "COMPLETE 0\nBAD your a \nGOOD you're a \n" "COMPLETE 0\nBAD your an \nGOOD you're an \n" "BAD youre\nGOOD you're\n" "COMPLETE 0\nBAD you;re \nGOOD you're \n" "COMPLETE 0\nBAD you're own \nGOOD your own \n" "COMPLETE 0\nBAD your her \nGOOD you're her \n" "COMPLETE 0\nBAD your here \nGOOD you're here \n" "COMPLETE 0\nBAD your his \nGOOD you're his \n" "COMPLETE 0\nBAD your my \nGOOD you're my \n" "COMPLETE 0\nBAD your the \nGOOD you're the \n" "COMPLETE 0\nBAD your their \nGOOD you're their \n" "COMPLETE 0\nBAD your your \nGOOD you're your \n" "BAD youve\nGOOD you've\n" "COMPLETE 0\nBAD you;ve \nGOOD you've \n" "BAD ytou\nGOOD you\n" "BAD yuo\nGOOD you\n" "BAD yuor\nGOOD your\n"; gchar *buf; gchar *ibuf; GHashTable *hashes; char bad[82] = ""; char good[256] = ""; int pnt = 0; gsize size; gboolean complete = TRUE; gboolean case_sensitive = FALSE; buf = g_build_filename(purple_user_dir(), "dict", NULL); g_file_get_contents(buf, &ibuf, &size, NULL); g_free(buf); if (!ibuf) { ibuf = g_strdup(defaultconf); size = strlen(defaultconf); } model = gtk_list_store_new((gint)N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN); hashes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); while (buf_get_line(ibuf, &buf, &pnt, size)) { if (*buf != '#') { if (!strncasecmp(buf, "BAD ", 4)) { strncpy(bad, buf + 4, 81); } else if(!strncasecmp(buf, "CASE ", 5)) { case_sensitive = *(buf+5) == '0' ? FALSE : TRUE; } else if(!strncasecmp(buf, "COMPLETE ", 9)) { complete = *(buf+9) == '0' ? FALSE : TRUE; } else if (!strncasecmp(buf, "GOOD ", 5)) { strncpy(good, buf + 5, 255); if (*bad && *good && g_hash_table_lookup(hashes, bad) == NULL) { GtkTreeIter iter; /* We don't actually need to store the good string, since this * hash is just being used to eliminate duplicate bad strings. * The value has to be non-NULL so the lookup above will work. */ g_hash_table_insert(hashes, g_strdup(bad), GINT_TO_POINTER(1)); if (!complete) case_sensitive = TRUE; gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, BAD_COLUMN, bad, GOOD_COLUMN, good, WORD_ONLY_COLUMN, complete, CASE_SENSITIVE_COLUMN, case_sensitive, -1); } bad[0] = '\0'; complete = TRUE; case_sensitive = FALSE; } } } g_free(ibuf); g_hash_table_destroy(hashes); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), 0, GTK_SORT_ASCENDING);}static GtkWidget *tree;static GtkWidget *bad_entry;static GtkWidget *good_entry;static GtkWidget *complete_toggle;static GtkWidget *case_toggle;static void save_list(void);static void on_edited(GtkCellRendererText *cellrenderertext, gchar *path, gchar *arg2, gpointer data){ GtkTreeIter iter; GValue val; if (arg2[0] == '\0') { gdk_beep(); return; } g_return_if_fail(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &iter, path)); val.g_type = 0; 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); save_list(); } g_value_unset(&val);}static void word_only_toggled(GtkCellRendererToggle *cellrenderertoggle, gchar *path, gpointer data){ GtkTreeIter iter; gboolean enabled; g_return_if_fail(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &iter, path)); gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, WORD_ONLY_COLUMN, &enabled, -1); gtk_list_store_set(GTK_LIST_STORE(model), &iter, WORD_ONLY_COLUMN, !enabled, -1); /* I want to be sure that the above change has happened to the GtkTreeView first. */ gtk_list_store_set(GTK_LIST_STORE(model), &iter, CASE_SENSITIVE_COLUMN, enabled, -1); save_list();}static void case_sensitive_toggled(GtkCellRendererToggle *cellrenderertoggle, gchar *path, gpointer data){ GtkTreeIter iter; gboolean enabled; g_return_if_fail(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &iter, path)); /* Prevent the case sensitive column from changing on non-whole word replacements. * Ideally, the column would be set insensitive in the word_only_toggled callback. */ gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, WORD_ONLY_COLUMN, &enabled, -1); if (!enabled) return; gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CASE_SENSITIVE_COLUMN, &enabled, -1); gtk_list_store_set(GTK_LIST_STORE(model), &iter, CASE_SENSITIVE_COLUMN, !enabled, -1); save_list();}static void list_add_new(){ GtkTreeIter iter; const char *word = gtk_entry_get_text(GTK_ENTRY(bad_entry)); gboolean case_sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(case_toggle)); if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) { char *tmpword = g_utf8_casefold(word, -1); do { GValue bad_val; gboolean match; bad_val.g_type = 0; gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, BAD_COLUMN, &bad_val); if (case_sensitive) { GValue case_sensitive_val; case_sensitive_val.g_type = 0; gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, CASE_SENSITIVE_COLUMN, &case_sensitive_val); /* If they're both case-sensitive, then compare directly. * Otherwise, they overlap. */ if (g_value_get_boolean(&case_sensitive_val)) { match = !strcmp(g_value_get_string(&bad_val), word); } else { char *bad = g_utf8_casefold(g_value_get_string(&bad_val), -1); match = !strcmp(bad, tmpword); g_free(bad); } g_value_unset(&case_sensitive_val); } else { char *bad = g_utf8_casefold(g_value_get_string(&bad_val), -1); match = !strcmp(bad, tmpword); g_free(bad); } if (match) { g_value_unset(&bad_val); g_free(tmpword); purple_notify_error(NULL, _("Duplicate Correction"), _("The specified word already exists in the correction list."), gtk_entry_get_text(GTK_ENTRY(bad_entry))); return; } g_value_unset(&bad_val); } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)); g_free(tmpword); } gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, BAD_COLUMN, word, GOOD_COLUMN, gtk_entry_get_text(GTK_ENTRY(good_entry)), WORD_ONLY_COLUMN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(complete_toggle)), CASE_SENSITIVE_COLUMN, case_sensitive, -1); gtk_editable_delete_text(GTK_EDITABLE(bad_entry), 0, -1); gtk_editable_delete_text(GTK_EDITABLE(good_entry), 0, -1); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(complete_toggle), TRUE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(case_toggle), FALSE); gtk_widget_grab_focus(bad_entry); save_list();}static void add_selected_row_to_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data){ GtkTreeRowReference *row_reference; GSList **list = (GSList **)data; row_reference = gtk_tree_row_reference_new(model, path); *list = g_slist_prepend(*list, row_reference);}static void remove_row(void *data1, gpointer data2){ GtkTreeRowReference *row_reference; GtkTreePath *path; GtkTreeIter iter; row_reference = (GtkTreeRowReference *)data1; path = gtk_tree_row_reference_get_path(row_reference); if (gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path)) gtk_list_store_remove(model, &iter); gtk_tree_path_free(path); gtk_tree_row_reference_free(row_reference);}static void list_delete(){ GtkTreeSelection *sel; GSList *list = NULL; 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); g_slist_free(list); save_list();}static void save_list(){ GString *data; GtkTreeIter iter; data = g_string_new(""); if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) { do { GValue val0; GValue val1; GValue val2; GValue val3; val0.g_type = 0; val1.g_type = 0; val2.g_type = 0; val3.g_type = 0; gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, BAD_COLUMN, &val0); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, GOOD_COLUMN, &val1); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, WORD_ONLY_COLUMN, &val2); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, CASE_SENSITIVE_COLUMN, &val3); g_string_append_printf(data, "COMPLETE %d\nCASE %d\nBAD %s\nGOOD %s\n\n", g_value_get_boolean(&val2), g_value_get_boolean(&val3), g_value_get_string(&val0), g_value_get_string(&val1)); g_value_unset(&val0); g_value_unset(&val1); g_value_unset(&val2); g_value_unset(&val3); } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)); } purple_util_write_data_to_file("dict", data->str, -1); g_string_free(data, TRUE);}#if !GTK_CHECK_VERSION(2,2,0)static voidcount_selected_helper(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data){ (*(gint *)user_data)++;}#endifstatic void on_selection_changed(GtkTreeSelection *sel, gpointer data){ gint num_selected;#if GTK_CHECK_VERSION(2,2,0) num_selected = gtk_tree_selection_count_selected_rows(sel);#else gtk_tree_selection_selected_foreach(sel, count_selected_helper, &num_selected);#endif gtk_widget_set_sensitive((GtkWidget*)data, (num_selected > 0));}static gboolean non_empty(const char *s){ while (*s && g_ascii_isspace(*s)) s++; return *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))));}/* * EXPORTED FUNCTIONS */static gbooleanplugin_load(PurplePlugin *plugin){ void *conv_handle = purple_conversations_get_handle(); GList *convs; load_conf(); /* Attach to existing conversations */ for (convs = purple_get_conversations(); convs != NULL; convs = convs->next) { spellchk_new_attach((PurpleConversation *)convs->data); } purple_signal_connect(conv_handle, "conversation-created", plugin, PURPLE_CALLBACK(spellchk_new_attach), NULL); return TRUE;}static gbooleanplugin_unload(PurplePlugin *plugin){ GList *convs; /* Detach from existing conversations */ for (convs = purple_get_conversations(); convs != NULL; convs = convs->next) { PidginConversation *gtkconv = PIDGIN_CONVERSATION((PurpleConversation *)convs->data); spellchk *spell = g_object_get_data(G_OBJECT(gtkconv->entry), SPELLCHK_OBJECT_KEY); g_signal_handlers_disconnect_by_func(gtkconv->entry, message_send_cb, spell); g_object_set_data(G_OBJECT(gtkconv->entry), SPELLCHK_OBJECT_KEY, NULL); } return TRUE;}static void whole_words_button_toggled(GtkToggleButton *complete_toggle, GtkToggleButton *case_toggle){ gboolean enabled = gtk_toggle_button_get_active(complete_toggle); gtk_toggle_button_set_active(case_toggle, !enabled); gtk_widget_set_sensitive(GTK_WIDGET(case_toggle), enabled);}static GtkWidget *get_config_frame(PurplePlugin *plugin){ GtkWidget *ret, *vbox, *win; GtkWidget *hbox, *label; GtkWidget *button; GtkSizeGroup *sg; GtkSizeGroup *sg2; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkWidget *vbox2; GtkWidget *hbox2; GtkWidget *vbox3; ret = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE); gtk_container_set_border_width (GTK_CONTAINER(ret), PIDGIN_HIG_BORDER); vbox = pidgin_make_frame(ret, _("Text Replacements")); gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); gtk_widget_show(vbox); win
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -