diff src/gtkrequest.c @ 13360:2e6dda9f9159

[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 <tailor@pidgin.im>
author Richard Laager <rlaager@wiktel.com>
date Wed, 01 Mar 2006 06:10:41 +0000
parents d278dac585a5
children 9b4a80566fd5
line wrap: on
line diff
--- 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 <gdk/gdkkeysyms.h>
 
-#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);