# HG changeset patch # User Richard Laager # Date 1141193441 0 # Node ID 2e6dda9f91591c45215f613a35b3ef45a472e8ce # Parent ca250092a23ade63e94eb009c429227833707e19 [gaim-migrate @ 15733] SF Patch #1440729 from Sadrul Closes SF Feature Request #1414706 "This moves some stuff from gtkrequest.c to gtkutils.c -- this allows to setup autocomplete for entries that deal with screen-names of the buddies. I have used this function in the pounce dialog -- so now it has auto-complete." committer: Tailor Script diff -r ca250092a23a -r 2e6dda9f9159 plugins/ChangeLog.API --- a/plugins/ChangeLog.API Wed Mar 01 06:08:19 2006 +0000 +++ b/plugins/ChangeLog.API Wed Mar 01 06:10:41 2006 +0000 @@ -276,6 +276,7 @@ * GaimRequestType: Added GAIM_REQUEST_FOLDER * GaimRequestUiOps: Added request_folder * gaim_request_folder() + * gaim_gtk_setup_screenname_autocomplete() Signals - Changed: (See the Doxygen docs for details on all signals.) * Signal propagation now stops after a handler returns a non-NULL value. diff -r ca250092a23a -r 2e6dda9f9159 src/gtkpounce.c --- a/src/gtkpounce.c Wed Mar 01 06:08:19 2006 +0000 +++ b/src/gtkpounce.c Wed Mar 01 06:10:41 2006 +0000 @@ -552,6 +552,8 @@ dialog->buddy_entry = gtk_entry_new(); + gaim_gtk_setup_screenname_autocomplete(dialog->buddy_entry, dialog->account_menu, FALSE); + gtk_box_pack_start(GTK_BOX(hbox), dialog->buddy_entry, TRUE, TRUE, 0); gtk_widget_show(dialog->buddy_entry); diff -r ca250092a23a -r 2e6dda9f9159 src/gtkrequest.c --- a/src/gtkrequest.c Wed Mar 01 06:08:19 2006 +0000 +++ b/src/gtkrequest.c Wed Mar 01 06:10:41 2006 +0000 @@ -36,9 +36,7 @@ #include -#if GTK_CHECK_VERSION(2,3,0) -# define NEW_STYLE_COMPLETION -#endif +static GtkWidget * create_account_field(GaimRequestField *field); typedef struct { @@ -80,16 +78,6 @@ } GaimGtkRequestData; -#ifndef NEW_STYLE_COMPLETION -typedef struct -{ - GCompletion *completion; - - gboolean completion_started; - -} GaimGtkCompletionData; -#endif - static void generic_response_start(GaimGtkRequestData *data) { @@ -677,396 +665,6 @@ gaim_request_fields_all_required_filled(field->group->fields_list)); } -#ifndef NEW_STYLE_COMPLETION -static gboolean -completion_entry_event(GtkEditable *entry, GdkEventKey *event, - GaimGtkCompletionData *data) -{ - int pos, end_pos; - - if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Tab) - { - gtk_editable_get_selection_bounds(entry, &pos, &end_pos); - - if (data->completion_started && - pos != end_pos && pos > 1 && - end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry)))) - { - gtk_editable_select_region(entry, 0, 0); - gtk_editable_set_position(entry, -1); - - return TRUE; - } - } - else if (event->type == GDK_KEY_PRESS && event->length > 0) - { - char *prefix, *nprefix; - - gtk_editable_get_selection_bounds(entry, &pos, &end_pos); - - if (data->completion_started && - pos != end_pos && pos > 1 && - end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry)))) - { - char *temp; - - temp = gtk_editable_get_chars(entry, 0, pos); - prefix = g_strconcat(temp, event->string, NULL); - g_free(temp); - } - else if (pos == end_pos && pos > 1 && - end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry)))) - { - prefix = g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry)), - event->string, NULL); - } - else - return FALSE; - - pos = strlen(prefix); - nprefix = NULL; - - g_completion_complete(data->completion, prefix, &nprefix); - - if (nprefix != NULL) - { - gtk_entry_set_text(GTK_ENTRY(entry), nprefix); - gtk_editable_set_position(entry, pos); - gtk_editable_select_region(entry, pos, -1); - - data->completion_started = TRUE; - - g_free(nprefix); - g_free(prefix); - - return TRUE; - } - - g_free(prefix); - } - - return FALSE; -} - -static void -destroy_completion_data(GtkWidget *w, GaimGtkCompletionData *data) -{ - g_list_foreach(data->completion->items, (GFunc)g_free, NULL); - g_completion_free(data->completion); - - g_free(data); -} -#endif /* !NEW_STYLE_COMPLETION */ - -#ifdef NEW_STYLE_COMPLETION -static gboolean screenname_completion_match_func(GtkEntryCompletion *completion, - const gchar *key, GtkTreeIter *iter, gpointer user_data) -{ - GtkTreeModel *model; - GValue val1; - GValue val2; - const char *tmp; - - model = gtk_entry_completion_get_model (completion); - - val1.g_type = 0; - gtk_tree_model_get_value(model, iter, 2, &val1); - tmp = g_value_get_string(&val1); - if (tmp != NULL && gaim_str_has_prefix(tmp, key)) - { - g_value_unset(&val1); - return TRUE; - } - g_value_unset(&val1); - - val2.g_type = 0; - gtk_tree_model_get_value(model, iter, 3, &val2); - tmp = g_value_get_string(&val2); - if (tmp != NULL && gaim_str_has_prefix(tmp, key)) - { - g_value_unset(&val2); - return TRUE; - } - g_value_unset(&val2); - - return FALSE; -} - -static gboolean screenname_completion_match_selected_cb(GtkEntryCompletion *completion, - GtkTreeModel *model, GtkTreeIter *iter, gpointer *user_data) -{ - GValue val; - GaimRequestField *screen_field = user_data[1]; - GList *fields = screen_field->group->fields; - GaimAccount *account; - - val.g_type = 0; - gtk_tree_model_get_value(model, iter, 1, &val); - gtk_entry_set_text(GTK_ENTRY(user_data[0]), g_value_get_string(&val)); - g_value_unset(&val); - - gtk_tree_model_get_value(model, iter, 4, &val); - account = g_value_get_pointer(&val); - g_value_unset(&val); - - if (account == NULL) - return TRUE; - - do { - GaimRequestField *field = fields->data; - - if (gaim_request_field_get_type(field) == GAIM_REQUEST_FIELD_ACCOUNT) { - const char *type_hint = gaim_request_field_get_type_hint(field); - - if (type_hint != NULL && !strcmp(type_hint, "account")) { - /* We found the corresponding account field. */ - GtkOptionMenu *optmenu = GTK_OPTION_MENU(field->ui_data); - - /* Set the account in the request API. */ - gaim_request_field_account_set_value(field, account); - - if (optmenu != NULL) { - GList *items = GTK_MENU_SHELL(gtk_option_menu_get_menu(optmenu))->children; - guint index = 0; - - do { - if (account == g_object_get_data(G_OBJECT(items->data), "account")) { - /* Set the account in the GUI. */ - gtk_option_menu_set_history(GTK_OPTION_MENU(field->ui_data), index); - return TRUE; - } - index++; - } while ((items = items->next) != NULL); - } - - return TRUE; - } - } - - } while ((fields = fields->next) != NULL); - - return TRUE; -} - -static void -add_screenname_autocomplete_entry(GtkListStore *store, const char *buddy_alias, const char *contact_alias, - const GaimAccount *account, const char *screenname) -{ - GtkTreeIter iter; - gboolean completion_added = FALSE; - gchar *normalized_screenname; - gchar *tmp; - - tmp = g_utf8_normalize(screenname, -1, G_NORMALIZE_DEFAULT); - normalized_screenname = g_utf8_casefold(tmp, -1); - g_free(tmp); - - /* There's no sense listing things like: 'xxx "xxx"' - when the screenname and buddy alias match. */ - if (buddy_alias && strcmp(buddy_alias, screenname)) { - char *completion_entry = g_strdup_printf("%s \"%s\"", screenname, buddy_alias); - char *tmp2 = g_utf8_normalize(buddy_alias, -1, G_NORMALIZE_DEFAULT); - - tmp = g_utf8_casefold(tmp2, -1); - g_free(tmp2); - - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - 0, completion_entry, - 1, screenname, - 2, normalized_screenname, - 3, tmp, - 4, account, - -1); - g_free(completion_entry); - g_free(tmp); - completion_added = TRUE; - } - - /* There's no sense listing things like: 'xxx "xxx"' - when the screenname and contact alias match. */ - if (contact_alias && strcmp(contact_alias, screenname)) { - /* We don't want duplicates when the contact and buddy alias match. */ - if (!buddy_alias || strcmp(contact_alias, buddy_alias)) { - char *completion_entry = g_strdup_printf("%s \"%s\"", - screenname, contact_alias); - char *tmp2 = g_utf8_normalize(contact_alias, -1, G_NORMALIZE_DEFAULT); - - tmp = g_utf8_casefold(tmp2, -1); - g_free(tmp2); - - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - 0, completion_entry, - 1, screenname, - 2, normalized_screenname, - 3, tmp, - 4, account, - -1); - g_free(completion_entry); - g_free(tmp); - completion_added = TRUE; - } - } - - if (completion_added == FALSE) { - /* Add the buddy's screenname. */ - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - 0, screenname, - 1, screenname, - 2, normalized_screenname, - 3, NULL, - 4, account, - -1); - } - - g_free(normalized_screenname); -} -#endif /* NEW_STYLE_COMPLETION */ - -static void get_log_set_name(GaimLogSet *set, gpointer value, gpointer **set_hash_data) -{ - /* 1. Don't show buddies because we will have gotten them already. - * 2. Only show those with non-NULL accounts that are currently connected. - * 3. The boxes that use this autocomplete code handle only IMs. */ - if (!set->buddy && - (GPOINTER_TO_INT(set_hash_data[1]) || - (set->account != NULL && gaim_account_is_connected(set->account))) && - set->type == GAIM_LOG_IM) { -#ifdef NEW_STYLE_COMPLETION - add_screenname_autocomplete_entry((GtkListStore *)set_hash_data[0], - NULL, NULL, set->account, set->name); -#else - GList **items = ((GList **)set_hash_data[0]); - /* Steal the name for the GCompletion. */ - *items = g_list_append(*items, set->name); - set->name = set->normalized_name = NULL; -#endif /* NEW_STYLE_COMPLETION */ - } -} - -static void -setup_screenname_autocomplete(GtkWidget *entry, GaimRequestField *field, gboolean all) -{ -#ifdef NEW_STYLE_COMPLETION - /* Store the displayed completion value, the screenname, the UTF-8 normalized & casefolded screenname, - * the UTF-8 normalized & casefolded value for comparison, and the account. */ - GtkListStore *store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); - - GaimBlistNode *gnode, *cnode, *bnode; - GHashTable *sets; - gpointer set_hash_data[] = {store, GINT_TO_POINTER(all)}; - GtkEntryCompletion *completion; - gpointer *data; - - for (gnode = gaim_get_blist()->root; gnode != NULL; gnode = gnode->next) - { - if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) - continue; - - for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) - { - if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) - continue; - - for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) - { - GaimBuddy *buddy = (GaimBuddy *)bnode; - - if (!all && !gaim_account_is_connected(buddy->account)) - continue; - - add_screenname_autocomplete_entry(store, - ((GaimContact *)cnode)->alias, - gaim_buddy_get_contact_alias(buddy), - buddy->account, - buddy->name - ); - } - } - } - - sets = gaim_log_get_log_sets(); - g_hash_table_foreach(sets, (GHFunc)get_log_set_name, &set_hash_data); - g_hash_table_destroy(sets); - - - /* Sort the completion list by screenname. */ - gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), - 1, GTK_SORT_ASCENDING); - - completion = gtk_entry_completion_new(); - gtk_entry_completion_set_match_func(completion, screenname_completion_match_func, NULL, NULL); - - data = g_new0(gpointer, 2); - data[0] = entry; - data[1] = field; - g_signal_connect(G_OBJECT(completion), "match-selected", - G_CALLBACK(screenname_completion_match_selected_cb), data); - - gtk_entry_set_completion(GTK_ENTRY(entry), completion); - g_object_unref(completion); - - gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store)); - g_object_unref(store); - - gtk_entry_completion_set_text_column(completion, 0); - -#else /* !NEW_STYLE_COMPLETION */ - GaimGtkCompletionData *data; - GaimBlistNode *gnode, *cnode, *bnode; - GList *item = g_list_append(NULL, NULL); - GHashTable *sets; - gpointer set_hash_data[2]; - - data = g_new0(GaimGtkCompletionData, 1); - - data->completion = g_completion_new(NULL); - - g_completion_set_compare(data->completion, g_ascii_strncasecmp); - - for (gnode = gaim_get_blist()->root; gnode != NULL; gnode = gnode->next) - { - if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) - continue; - - for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) - { - if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) - continue; - - for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) - { - GaimBuddy *buddy = (GaimBuddy *)bnode; - - if (!all && !gaim_account_is_connected(buddy->account)) - continue; - - item->data = g_strdup(buddy->name); - g_completion_add_items(data->completion, item); - } - } - } - g_list_free(item); - - sets = gaim_log_get_log_sets(); - item = NULL; - set_hash_data[0] = &item; - set_hash_data[1] = GINT_TO_POINTER(all); - g_hash_table_foreach(sets, (GHFunc)get_log_set_name, &set_hash_data); - g_hash_table_destroy(sets); - g_completion_add_items(data->completion, item); - g_list_free(item); - - g_signal_connect(G_OBJECT(entry), "event", - G_CALLBACK(completion_entry_event), data); - g_signal_connect(G_OBJECT(entry), "destroy", - G_CALLBACK(destroy_completion_data), data); - -#endif /* !NEW_STYLE_COMPLETION */ -} - static void setup_entry_field(GtkWidget *entry, GaimRequestField *field) { @@ -1082,9 +680,28 @@ if ((type_hint = gaim_request_field_get_type_hint(field)) != NULL) { - if (!strncmp(type_hint, "screenname", sizeof("screenname") - 1)) + if (gaim_str_has_prefix(type_hint, "screenname")) { - setup_screenname_autocomplete(entry, field, !strcmp(type_hint, "screenname-all")); + GtkWidget *optmenu = NULL; + GList *fields = field->group->fields; + while (fields) + { + GaimRequestField *fld = fields->data; + fields = fields->next; + + if (gaim_request_field_get_type(fld) == GAIM_REQUEST_FIELD_ACCOUNT) + { + const char *type_hint = gaim_request_field_get_type_hint(fld); + if (type_hint != NULL && strcmp(type_hint, "account") == 0) + { + if (fld->ui_data == NULL) + fld->ui_data - create_account_field(fld); + optmenu = GTK_WIDGET(fld->ui_data); + break; + } + } + } + gaim_gtk_setup_screenname_autocomplete(entry, optmenu, !strcmp(type_hint, "screenname-all")); } } } @@ -1661,7 +1278,9 @@ gtk_widget_show(label); } - if (type == GAIM_REQUEST_FIELD_STRING) + if (field->ui_data != NULL) + widget = GTK_WIDGET(field->ui_data); + else if (type == GAIM_REQUEST_FIELD_STRING) widget = create_string_field(field); else if (type == GAIM_REQUEST_FIELD_INTEGER) widget = create_int_field(field); diff -r ca250092a23a -r 2e6dda9f9159 src/gtkutils.c --- a/src/gtkutils.c Wed Mar 01 06:08:19 2006 +0000 +++ b/src/gtkutils.c Wed Mar 01 06:10:41 2006 +0000 @@ -1734,3 +1734,398 @@ gaim_menu_action_free(act); } } + + +#if GTK_CHECK_VERSION(2,3,0) +# define NEW_STYLE_COMPLETION +#endif + +#ifndef NEW_STYLE_COMPLETION +typedef struct +{ + GCompletion *completion; + + gboolean completion_started; + +} GaimGtkCompletionData; +#endif + +#ifndef NEW_STYLE_COMPLETION +static gboolean +completion_entry_event(GtkEditable *entry, GdkEventKey *event, + GaimGtkCompletionData *data) +{ + int pos, end_pos; + + if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Tab) + { + gtk_editable_get_selection_bounds(entry, &pos, &end_pos); + + if (data->completion_started && + pos != end_pos && pos > 1 && + end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry)))) + { + gtk_editable_select_region(entry, 0, 0); + gtk_editable_set_position(entry, -1); + + return TRUE; + } + } + else if (event->type == GDK_KEY_PRESS && event->length > 0) + { + char *prefix, *nprefix; + + gtk_editable_get_selection_bounds(entry, &pos, &end_pos); + + if (data->completion_started && + pos != end_pos && pos > 1 && + end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry)))) + { + char *temp; + + temp = gtk_editable_get_chars(entry, 0, pos); + prefix = g_strconcat(temp, event->string, NULL); + g_free(temp); + } + else if (pos == end_pos && pos > 1 && + end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry)))) + { + prefix = g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry)), + event->string, NULL); + } + else + return FALSE; + + pos = strlen(prefix); + nprefix = NULL; + + g_completion_complete(data->completion, prefix, &nprefix); + + if (nprefix != NULL) + { + gtk_entry_set_text(GTK_ENTRY(entry), nprefix); + gtk_editable_set_position(entry, pos); + gtk_editable_select_region(entry, pos, -1); + + data->completion_started = TRUE; + + g_free(nprefix); + g_free(prefix); + + return TRUE; + } + + g_free(prefix); + } + + return FALSE; +} + +static void +destroy_completion_data(GtkWidget *w, GaimGtkCompletionData *data) +{ + g_list_foreach(data->completion->items, (GFunc)g_free, NULL); + g_completion_free(data->completion); + + g_free(data); +} +#endif /* !NEW_STYLE_COMPLETION */ + +#ifdef NEW_STYLE_COMPLETION +static gboolean screenname_completion_match_func(GtkEntryCompletion *completion, + const gchar *key, GtkTreeIter *iter, gpointer user_data) +{ + GtkTreeModel *model; + GValue val1; + GValue val2; + const char *tmp; + + model = gtk_entry_completion_get_model (completion); + + val1.g_type = 0; + gtk_tree_model_get_value(model, iter, 2, &val1); + tmp = g_value_get_string(&val1); + if (tmp != NULL && gaim_str_has_prefix(tmp, key)) + { + g_value_unset(&val1); + return TRUE; + } + g_value_unset(&val1); + + val2.g_type = 0; + gtk_tree_model_get_value(model, iter, 3, &val2); + tmp = g_value_get_string(&val2); + if (tmp != NULL && gaim_str_has_prefix(tmp, key)) + { + g_value_unset(&val2); + return TRUE; + } + g_value_unset(&val2); + + return FALSE; +} + +static gboolean screenname_completion_match_selected_cb(GtkEntryCompletion *completion, + GtkTreeModel *model, GtkTreeIter *iter, gpointer *user_data) +{ + GValue val; + GtkWidget *optmenu = user_data[1]; + GaimAccount *account; + + val.g_type = 0; + gtk_tree_model_get_value(model, iter, 1, &val); + gtk_entry_set_text(GTK_ENTRY(user_data[0]), g_value_get_string(&val)); + g_value_unset(&val); + + gtk_tree_model_get_value(model, iter, 4, &val); + account = g_value_get_pointer(&val); + g_value_unset(&val); + + if (account == NULL) + return TRUE; + + if (optmenu != NULL) { + gaim_gtk_account_option_menu_set_selected(optmenu, account); + GList *items = GTK_MENU_SHELL(gtk_option_menu_get_menu(GTK_OPTION_MENU(optmenu)))->children; + guint index = 0; + + do { + if (account == g_object_get_data(G_OBJECT(items->data), "account")) { + /* Set the account in the GUI. */ + gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), index); + return TRUE; + } + index++; + } while ((items = items->next) != NULL); + } + + return TRUE; +} + +static void +add_screenname_autocomplete_entry(GtkListStore *store, const char *buddy_alias, const char *contact_alias, + const GaimAccount *account, const char *screenname) +{ + GtkTreeIter iter; + gboolean completion_added = FALSE; + gchar *normalized_screenname; + gchar *tmp; + + tmp = g_utf8_normalize(screenname, -1, G_NORMALIZE_DEFAULT); + normalized_screenname = g_utf8_casefold(tmp, -1); + g_free(tmp); + + /* There's no sense listing things like: 'xxx "xxx"' + when the screenname and buddy alias match. */ + if (buddy_alias && strcmp(buddy_alias, screenname)) { + char *completion_entry = g_strdup_printf("%s \"%s\"", screenname, buddy_alias); + char *tmp2 = g_utf8_normalize(buddy_alias, -1, G_NORMALIZE_DEFAULT); + + tmp = g_utf8_casefold(tmp2, -1); + g_free(tmp2); + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, completion_entry, + 1, screenname, + 2, normalized_screenname, + 3, tmp, + 4, account, + -1); + g_free(completion_entry); + g_free(tmp); + completion_added = TRUE; + } + + /* There's no sense listing things like: 'xxx "xxx"' + when the screenname and contact alias match. */ + if (contact_alias && strcmp(contact_alias, screenname)) { + /* We don't want duplicates when the contact and buddy alias match. */ + if (!buddy_alias || strcmp(contact_alias, buddy_alias)) { + char *completion_entry = g_strdup_printf("%s \"%s\"", + screenname, contact_alias); + char *tmp2 = g_utf8_normalize(contact_alias, -1, G_NORMALIZE_DEFAULT); + + tmp = g_utf8_casefold(tmp2, -1); + g_free(tmp2); + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, completion_entry, + 1, screenname, + 2, normalized_screenname, + 3, tmp, + 4, account, + -1); + g_free(completion_entry); + g_free(tmp); + completion_added = TRUE; + } + } + + if (completion_added == FALSE) { + /* Add the buddy's screenname. */ + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + 0, screenname, + 1, screenname, + 2, normalized_screenname, + 3, NULL, + 4, account, + -1); + } + + g_free(normalized_screenname); +} +#endif /* NEW_STYLE_COMPLETION */ + +static void get_log_set_name(GaimLogSet *set, gpointer value, gpointer **set_hash_data) +{ + /* 1. Don't show buddies because we will have gotten them already. + * 2. Only show those with non-NULL accounts that are currently connected. + * 3. The boxes that use this autocomplete code handle only IMs. */ + if (!set->buddy && + (GPOINTER_TO_INT(set_hash_data[1]) || + (set->account != NULL && gaim_account_is_connected(set->account))) && + set->type == GAIM_LOG_IM) { +#ifdef NEW_STYLE_COMPLETION + add_screenname_autocomplete_entry((GtkListStore *)set_hash_data[0], + NULL, NULL, set->account, set->name); +#else + GList **items = ((GList **)set_hash_data[0]); + /* Steal the name for the GCompletion. */ + *items = g_list_append(*items, set->name); + set->name = set->normalized_name = NULL; +#endif /* NEW_STYLE_COMPLETION */ + } +} + +void +gaim_gtk_setup_screenname_autocomplete(GtkWidget *entry, GtkWidget *accountopt, gboolean all) +{ +#ifdef NEW_STYLE_COMPLETION + /* Store the displayed completion value, the screenname, the UTF-8 normalized & casefolded screenname, + * the UTF-8 normalized & casefolded value for comparison, and the account. */ + GtkListStore *store; + + GaimBlistNode *gnode, *cnode, *bnode; + GHashTable *sets; + gpointer set_hash_data[2]; + GtkEntryCompletion *completion; + gpointer *data; + + g_return_if_fail(entry != NULL); + + store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); + set_hash_data[0] = store; + set_hash_data[1] = GINT_TO_POINTER(all); + + for (gnode = gaim_get_blist()->root; gnode != NULL; gnode = gnode->next) + { + if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) + continue; + + for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) + { + if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) + continue; + + for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) + { + GaimBuddy *buddy = (GaimBuddy *)bnode; + + if (!all && !gaim_account_is_connected(buddy->account)) + continue; + + add_screenname_autocomplete_entry(store, + ((GaimContact *)cnode)->alias, + gaim_buddy_get_contact_alias(buddy), + buddy->account, + buddy->name + ); + } + } + } + + sets = gaim_log_get_log_sets(); + g_hash_table_foreach(sets, (GHFunc)get_log_set_name, &set_hash_data); + g_hash_table_destroy(sets); + + + /* Sort the completion list by screenname. */ + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), + 1, GTK_SORT_ASCENDING); + + completion = gtk_entry_completion_new(); + gtk_entry_completion_set_match_func(completion, screenname_completion_match_func, NULL, NULL); + + data = g_new0(gpointer, 2); + data[0] = entry; + data[1] = accountopt; + g_signal_connect(G_OBJECT(completion), "match-selected", + G_CALLBACK(screenname_completion_match_selected_cb), data); + + gtk_entry_set_completion(GTK_ENTRY(entry), completion); + g_object_unref(completion); + + gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store)); + g_object_unref(store); + + gtk_entry_completion_set_text_column(completion, 0); + +#else /* !NEW_STYLE_COMPLETION */ + GaimGtkCompletionData *data; + GaimBlistNode *gnode, *cnode, *bnode; + GList *item = g_list_append(NULL, NULL); + GHashTable *sets; + gpointer set_hash_data[2]; + + g_return_if_fail(entry != NULL); + + data = g_new0(GaimGtkCompletionData, 1); + + data->completion = g_completion_new(NULL); + + g_completion_set_compare(data->completion, g_ascii_strncasecmp); + + for (gnode = gaim_get_blist()->root; gnode != NULL; gnode = gnode->next) + { + if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) + continue; + + for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) + { + if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) + continue; + + for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) + { + GaimBuddy *buddy = (GaimBuddy *)bnode; + + if (!all && !gaim_account_is_connected(buddy->account)) + continue; + + item->data = g_strdup(buddy->name); + g_completion_add_items(data->completion, item); + } + } + } + g_list_free(item); + + sets = gaim_log_get_log_sets(); + item = NULL; + set_hash_data[0] = &item; + set_hash_data[1] = GINT_TO_POINTER(all); + g_hash_table_foreach(sets, (GHFunc)get_log_set_name, &set_hash_data); + g_hash_table_destroy(sets); + g_completion_add_items(data->completion, item); + g_list_free(item); + + g_signal_connect(G_OBJECT(entry), "event", + G_CALLBACK(completion_entry_event), data); + g_signal_connect(G_OBJECT(entry), "destroy", + G_CALLBACK(destroy_completion_data), data); + +#endif /* !NEW_STYLE_COMPLETION */ +} + diff -r ca250092a23a -r 2e6dda9f9159 src/gtkutils.h --- a/src/gtkutils.h Wed Mar 01 06:08:19 2006 +0000 +++ b/src/gtkutils.h Wed Mar 01 06:10:41 2006 +0000 @@ -250,6 +250,17 @@ void gaim_gtk_account_option_menu_set_selected(GtkWidget *optmenu, GaimAccount *account); /** + * Add autocompletion of screenames to an entry. + * + * @param entry The GtkEntry on which to setup autocomplete. + * @param optmenu A menu for accounts, returned by gaim_gtk_account_option_menu_new(). + * If @a optmenu is not @c NULL, it'll be updated when a screenname is chosen + * from the autocomplete list. + * @param all Whether to include screennames from disconnected accounts. + */ +void gaim_gtk_setup_screenname_autocomplete(GtkWidget *entry, GtkWidget *optmenu, gboolean all); + +/** * Check if the given path is a directory or not. If it is, then modify * the given GtkFileSelection dialog so that it displays the given path. * If the given path is not a directory, then do nothing.