[evolution-data-server] Bug #345401 - Cannot include 2 emails from same contact in To: dialog



commit 43d11cba34803e4b0553ac54c628705345009548
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jan 20 11:58:00 2010 +0100

    Bug #345401 - Cannot include 2 emails from same contact in To: dialog

 libedataserverui/e-name-selector-dialog.c |   29 +++----
 libedataserverui/e-name-selector-model.c  |  135 ++++++++++++++++++++++++-----
 libedataserverui/e-name-selector-model.h  |    3 +
 3 files changed, 129 insertions(+), 38 deletions(-)
---
diff --git a/libedataserverui/e-name-selector-dialog.c b/libedataserverui/e-name-selector-dialog.c
index 620fe7a..ae8aec3 100644
--- a/libedataserverui/e-name-selector-dialog.c
+++ b/libedataserverui/e-name-selector-dialog.c
@@ -395,9 +395,17 @@ sort_iter_to_contact_store_iter (ENameSelectorDialog *name_selector_dialog, GtkT
 }
 
 static void
-add_destination (EDestinationStore *destination_store, EContact *contact, gint email_n)
+add_destination (ENameSelectorModel *name_selector_model, EDestinationStore *destination_store, EContact *contact, gint email_n)
 {
 	EDestination *destination;
+	GList *email_list, *nth;
+
+	/* get the correct index of an email in the contact */
+	email_list = e_name_selector_model_get_contact_emails_without_used (name_selector_model, contact, FALSE);
+	while (nth = g_list_nth (email_list, email_n), nth && nth->data == NULL) {
+		email_n++;
+	}
+	e_name_selector_model_free_emails_list (email_list);
 
 	/* Transfer (actually, copy into a destination and let the model filter out the
 	 * source automatically) */
@@ -873,7 +881,7 @@ contact_activated (ENameSelectorDialog *name_selector_dialog, GtkTreePath *path)
 		return;
 	}
 
-	add_destination (destination_store, contact, email_n);
+	add_destination (name_selector_dialog->name_selector_model, destination_store, contact, email_n);
 }
 
 static void
@@ -1044,7 +1052,7 @@ transfer_button_clicked (ENameSelectorDialog *name_selector_dialog, GtkButton *t
 			return;
 		}
 
-		add_destination (destination_store, contact, email_n);
+		add_destination (name_selector_dialog->name_selector_model, destination_store, contact, email_n);
 	}
 	g_list_free (rows);
 }
@@ -1142,17 +1150,6 @@ shutdown_name_selector_model (ENameSelectorDialog *name_selector_dialog)
 }
 
 static void
-deep_free_list (GList *list)
-{
-	GList *l;
-
-	for (l = list; l; l = g_list_next (l))
-		g_free (l->data);
-
-	g_list_free (list);
-}
-
-static void
 contact_column_formatter (GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model,
 			  GtkTreeIter *iter, ENameSelectorDialog *name_selector_dialog)
 {
@@ -1170,7 +1167,7 @@ contact_column_formatter (GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkT
 
 	contact_store = e_name_selector_model_peek_contact_store (name_selector_dialog->name_selector_model);
 	contact = e_contact_store_get_contact (contact_store, &contact_store_iter);
-	email_list = e_contact_get (contact, E_CONTACT_EMAIL);
+	email_list = e_name_selector_model_get_contact_emails_without_used (name_selector_dialog->name_selector_model, contact, TRUE);
 	email_str = g_list_nth_data (email_list, email_n);
 	full_name_str = e_contact_get (contact, E_CONTACT_FULL_NAME);
 
@@ -1183,7 +1180,7 @@ contact_column_formatter (GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkT
 	}
 
 	g_free (full_name_str);
-	deep_free_list (email_list);
+	e_name_selector_model_free_emails_list (email_list);
 
 	g_object_set (cell, "text", string, NULL);
 	g_free (string);
diff --git a/libedataserverui/e-name-selector-model.c b/libedataserverui/e-name-selector-model.c
index 70caac1..1a0d434 100644
--- a/libedataserverui/e-name-selector-model.c
+++ b/libedataserverui/e-name-selector-model.c
@@ -159,8 +159,7 @@ generate_contact_rows (EContactStore *contact_store, GtkTreeIter *iter,
 {
 	EContact    *contact;
 	const gchar *contact_uid;
-	gboolean     result = TRUE;
-	gint         n_rows;
+	gint         n_rows, used_rows = 0;
 	gint         i;
 
 	contact = e_contact_store_get_contact (contact_store, iter);
@@ -168,9 +167,9 @@ generate_contact_rows (EContactStore *contact_store, GtkTreeIter *iter,
 
 	contact_uid = e_contact_get_const (contact, E_CONTACT_UID);
 	if (!contact_uid)
-		return TRUE;  /* Can happen with broken databases */
+		return 0;  /* Can happen with broken databases */
 
-	for (i = 0; i < name_selector_model->sections->len && result == TRUE; i++) {
+	for (i = 0; i < name_selector_model->sections->len; i++) {
 		Section *section;
 		GList   *destinations;
 		GList   *l;
@@ -184,28 +183,25 @@ generate_contact_rows (EContactStore *contact_store, GtkTreeIter *iter,
 
 			destination_uid = e_destination_get_contact_uid (destination);
 			if (destination_uid && !strcmp (contact_uid, destination_uid)) {
-				result = FALSE;
-				break;
+				used_rows++;
 			}
 		}
 
 		g_list_free (destinations);
 	}
 
-	if (result) {
+	if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
+		n_rows = 1 - used_rows;
+	} else {
 		GList    *email_list;
 
-		if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
-			n_rows = 1;
-		} else {
-			email_list = e_contact_get (contact, E_CONTACT_EMAIL);
-			n_rows = g_list_length (email_list);
-			deep_free_list (email_list);
-		}
-	} else {
-		n_rows = 0;
+		email_list = e_contact_get (contact, E_CONTACT_EMAIL);
+		n_rows = g_list_length (email_list) - used_rows;
+		deep_free_list (email_list);
 	}
 
+	g_return_val_if_fail (n_rows >= 0, 0);
+
 	return n_rows;
 }
 
@@ -220,10 +216,11 @@ override_email_address (EContactStore *contact_store, GtkTreeIter *iter,
 		gchar    *email;
 
 		contact = e_contact_store_get_contact (contact_store, iter);
-		email_list = e_contact_get (contact, E_CONTACT_EMAIL);
+		email_list = e_name_selector_model_get_contact_emails_without_used (name_selector_model, contact, TRUE);
+		g_return_if_fail (g_list_length (email_list) <= permutation_n);
 		email = g_strdup (g_list_nth_data (email_list, permutation_n));
 		g_value_set_string (value, email);
-		deep_free_list (email_list);
+		e_name_selector_model_free_emails_list (email_list);
 	} else {
 		gtk_tree_model_get_value (GTK_TREE_MODEL (contact_store), iter, column, value);
 	}
@@ -241,18 +238,27 @@ typedef struct
 HashCompare;
 
 static void
-emit_destination_uid_changes_cb (const gchar *uid, gpointer value, HashCompare *hash_compare)
+emit_destination_uid_changes_cb (gchar *uid_num, gpointer value, HashCompare *hash_compare)
 {
 	EContactStore *contact_store = hash_compare->name_selector_model->contact_store;
 
-	if (!hash_compare->other_hash || !g_hash_table_lookup (hash_compare->other_hash, uid)) {
+	if (!hash_compare->other_hash || !g_hash_table_lookup (hash_compare->other_hash, uid_num)) {
 		GtkTreeIter  iter;
 		GtkTreePath *path;
+		gchar *sep;
+
+		sep = strrchr (uid_num, ':');
+		g_return_if_fail (sep != NULL);
+
+		*sep = '\0';
+		if (e_contact_store_find_contact (contact_store, uid_num, &iter)) {
+			*sep = ':';
 
-		if (e_contact_store_find_contact (contact_store, uid, &iter)) {
 			path = gtk_tree_model_get_path (GTK_TREE_MODEL (contact_store), &iter);
 			gtk_tree_model_row_changed (GTK_TREE_MODEL (contact_store), path, &iter);
 			gtk_tree_path_free (path);
+		} else {
+			*sep = ':';
 		}
 	}
 }
@@ -281,7 +287,7 @@ destinations_changed (ENameSelectorModel *name_selector_model)
 			destination_uid = e_destination_get_contact_uid (destination);
 			if (destination_uid)
 				g_hash_table_insert (destination_uid_hash_new,
-						     g_strdup (destination_uid),
+						     g_strdup_printf ("%s:%d", destination_uid, e_destination_get_email_num (destination)),
 						     GINT_TO_POINTER (TRUE));
 		}
 
@@ -520,3 +526,88 @@ e_name_selector_model_peek_section (ENameSelectorModel *name_selector_model, con
 
 	return TRUE;
 }
+
+/**
+ * e_name_selector_model_get_contact_emails_without_used:
+ * @name_selector_model: an #ENameSelectorModel
+ * @contact: to get emails from
+ * @remove_used: set to %TRUE to remove used from a list; or set to %FALSE to
+ * set used indexes to %NULL and keep them in the returned list
+ *
+ * Returns list of all email from @contact, without all used
+ * in any section. Each item is a string, an email address.
+ * Returned list should be freed with @e_name_selector_model_free_emails_list.
+ **/
+GList *
+e_name_selector_model_get_contact_emails_without_used (ENameSelectorModel *name_selector_model, EContact *contact, gboolean remove_used)
+{
+	GList *email_list;
+	gint emails;
+	gint i;
+	const gchar *contact_uid;
+
+	g_return_val_if_fail (name_selector_model != NULL, NULL);
+	g_return_val_if_fail (E_IS_NAME_SELECTOR_MODEL (name_selector_model), NULL);
+	g_return_val_if_fail (contact != NULL, NULL);
+	g_return_val_if_fail (E_IS_CONTACT (contact), NULL);
+
+	contact_uid = e_contact_get_const (contact, E_CONTACT_UID);
+	g_return_val_if_fail (contact_uid != NULL, NULL);
+
+	email_list = e_contact_get (contact, E_CONTACT_EMAIL);
+	emails = g_list_length (email_list);
+
+	for (i = 0; i < name_selector_model->sections->len; i++) {
+		Section *section;
+		GList   *destinations;
+		GList   *l;
+
+		section = &g_array_index (name_selector_model->sections, Section, i);
+		destinations = e_destination_store_list_destinations (section->destination_store);
+
+		for (l = destinations; l; l = g_list_next (l)) {
+			EDestination *destination = l->data;
+			const gchar  *destination_uid;
+
+			destination_uid = e_destination_get_contact_uid (destination);
+			if (destination_uid && !strcmp (contact_uid, destination_uid)) {
+				gint email_num = e_destination_get_email_num (destination);
+
+				if (email_num < 0 || email_num >= emails) {
+					g_warning ("%s: Destination's email_num %d out of bounds 0..%d", G_STRFUNC, email_num, emails - 1);
+				} else {
+					GList *nth = g_list_nth (email_list, email_num);
+
+					g_return_val_if_fail (nth != NULL, NULL);
+
+					g_free (nth->data);
+					nth->data = NULL;
+				}
+			}
+		}
+
+		g_list_free (destinations);
+	}
+
+	if (remove_used) {
+		/* remove all with data NULL, which are those used already */
+		do {
+			emails = g_list_length (email_list);
+			email_list = g_list_remove (email_list, NULL);
+		} while (g_list_length (email_list) != emails);
+	}
+
+	return email_list;
+}
+
+/**
+ * e_name_selector_model_free_emails_list:
+ * @email_list: list of emails returned from @e_name_selector_model_get_contact_emails_without_used
+ *
+ * Frees a list of emails returned from @e_name_selector_model_get_contact_emails_without_used.
+ **/
+void
+e_name_selector_model_free_emails_list (GList *email_list)
+{
+	deep_free_list (email_list);
+}
diff --git a/libedataserverui/e-name-selector-model.h b/libedataserverui/e-name-selector-model.h
index f0db09b..2b5ded3 100644
--- a/libedataserverui/e-name-selector-model.h
+++ b/libedataserverui/e-name-selector-model.h
@@ -78,6 +78,9 @@ void                 e_name_selector_model_add_section         (ENameSelectorMod
 void                 e_name_selector_model_remove_section      (ENameSelectorModel *name_selector_model,
 								const gchar *name);
 
+GList *e_name_selector_model_get_contact_emails_without_used (ENameSelectorModel *name_selector_model, EContact *contact, gboolean remove_used);
+void   e_name_selector_model_free_emails_list (GList *email_list);
+
 G_END_DECLS
 
 #endif /* E_NAME_SELECTOR_MODEL_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]