[evolution/wip/gsettings] Bug #224687 - Create lists of lists



commit 3fccaf1eab5c9e6a5db758d0f8670c965f3f5505
Author: Dan VrÃtil <dvratil redhat com>
Date:   Tue Jun 28 11:41:22 2011 +0200

    Bug #224687 - Create lists of lists

 addressbook/addressbook.error.xml                  |    7 +
 .../contact-list-editor/e-contact-list-editor.c    |  392 +++++++++-----------
 .../gui/contact-list-editor/e-contact-list-model.c |  162 +++++----
 .../gui/contact-list-editor/e-contact-list-model.h |   19 +-
 addressbook/gui/widgets/Makefile.am                |    2 +
 addressbook/gui/widgets/eab-contact-display.c      |  165 +++++++--
 6 files changed, 424 insertions(+), 323 deletions(-)
---
diff --git a/addressbook/addressbook.error.xml b/addressbook/addressbook.error.xml
index ab3a028..6a7dc4b 100644
--- a/addressbook/addressbook.error.xml
+++ b/addressbook/addressbook.error.xml
@@ -98,6 +98,13 @@
   <button stock="gtk-ok" _label="_Add" response="GTK_RESPONSE_YES"/>
  </error>
  
+ <error id="ask-list-add-list-exists" type="question" default="GTK_RESPONSE_NO">
+   <_primary>'{0}' is already in this contact list.</_primary>
+   <_secondary>A contact list named '{0}' is already in this contact list. Would you like to add it anyway?</_secondary>
+   <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/>
+   <button stock="gtk-ok" _label="_Add" response="GTK_RESPONSE_YES"/>
+ </error>
+ 
  <error id="server-version" type="warning">
   <_primary>Some features may not work properly with your current server</_primary> 
   <_secondary>You are connecting to an unsupported GroupWise server and may encounter problems using Evolution. For best results the server should be upgraded to a supported version</_secondary>
diff --git a/addressbook/gui/contact-list-editor/e-contact-list-editor.c b/addressbook/gui/contact-list-editor/e-contact-list-editor.c
index dc51011..c87d2e4 100644
--- a/addressbook/gui/contact-list-editor/e-contact-list-editor.c
+++ b/addressbook/gui/contact-list-editor/e-contact-list-editor.c
@@ -185,25 +185,59 @@ contact_list_editor_notify_cb (EContactListEditor *editor,
 	gtk_widget_set_sensitive (WIDGET (MEMBERS_VBOX), sensitive);
 }
 
-static void
-contact_list_editor_add_email (EContactListEditor *editor)
+static gboolean
+contact_list_editor_add_destination (GtkWidget *widget,
+				     EDestination *dest)
 {
-	EContactListEditorPrivate *priv = editor->priv;
-	EContactListModel *model;
-	GtkEntry *entry;
-	const gchar *text;
+	EContactListEditor *editor = contact_list_editor_extract (widget);
+	EContactListModel *model = E_CONTACT_LIST_MODEL (editor->priv->model);
+	EDestinationStore *dest_store;
+	GtkTreeView *treeview = GTK_TREE_VIEW (WIDGET (TREE_VIEW));
+	GtkTreePath *path;
 
-	entry = GTK_ENTRY (WIDGET (EMAIL_ENTRY));
-	model = E_CONTACT_LIST_MODEL (priv->model);
+	if (e_destination_is_evolution_list (dest)) {
+		const gchar *id = e_destination_get_contact_uid (dest);
+		const gchar *name = e_destination_get_name (dest);
+		const gchar *tag = "addressbook:ask-list-add-list-exists";
 
-	text = gtk_entry_get_text (entry);
-	if (text != NULL && *text != '\0') {
-		e_contact_list_model_add_email (model, text);
+		if (e_contact_list_model_has_uid (model, id) &&
+		    (e_alert_run_dialog_for_args (GTK_WINDOW (WIDGET (DIALOG)), tag, name, NULL) != GTK_RESPONSE_YES))
+			return FALSE;
+	} else {
+		const gchar *email = e_destination_get_email (dest);
+		const gchar *tag = "addressbook:ask-list-add-exists";
+
+		if (e_contact_list_model_has_email (model, email) &&
+		    (e_alert_run_dialog_for_args (GTK_WINDOW (WIDGET (DIALOG)), tag, email, NULL) != GTK_RESPONSE_YES))
+			return FALSE;
+	}
+
+	/* always add to the root level */
+	path = e_contact_list_model_add_destination (model, dest, NULL);
+	if (path) {
 		contact_list_editor_scroll_to_end (editor);
-		priv->changed = TRUE;
+		gtk_tree_view_expand_to_path (treeview, path);
+		gtk_tree_path_free (path);
+
+		dest_store = e_name_selector_entry_peek_destination_store (E_NAME_SELECTOR_ENTRY (WIDGET (EMAIL_ENTRY)));
+		e_destination_store_remove_destination (dest_store, dest);
+
+		return TRUE;
 	}
 
-	gtk_entry_set_text (entry, "");
+	return FALSE;
+}
+
+static void
+contact_list_editor_add_email (EContactListEditor *editor,
+			       const gchar *email)
+{
+	EContactListEditorPrivate *priv = editor->priv;
+
+	EDestination *dest = e_destination_new ();
+	e_destination_set_email (dest, email);
+	priv->changed = contact_list_editor_add_destination (WIDGET (DIALOG), dest) || priv->changed;
+
 	contact_list_editor_update (editor);
 }
 
@@ -251,19 +285,6 @@ exit:
 	g_object_unref (editor);
 }
 
-static gboolean
-contact_list_editor_contact_exists (EContactListModel *model,
-                                    const gchar *email)
-{
-	const gchar *tag = "addressbook:ask-list-add-exists";
-
-	if (!e_contact_list_model_has_email (model, email))
-		return FALSE;
-
-	return (e_alert_run_dialog_for_args (e_shell_get_active_window (NULL),
-					     tag, email, NULL) != GTK_RESPONSE_YES);
-}
-
 static void
 contact_list_editor_list_added_cb (EBookClient *book_client,
                                    const GError *error,
@@ -301,7 +322,7 @@ contact_list_editor_list_modified_cb (EBookClient *book_client,
                                       const GError *error,
                                       gpointer closure)
 {
-	EditorCloseStruct *ecs = closure;	
+	EditorCloseStruct *ecs = closure;
 	EContactListEditor *editor = ecs->editor;
 	EContactListEditorPrivate *priv = editor->priv;
 	gboolean should_close = ecs->should_close;
@@ -330,43 +351,28 @@ contact_list_editor_render_destination (GtkTreeViewColumn *column,
 	/* XXX Would be nice if EDestination had a text property
 	 *     that we could just bind the GtkCellRenderer to. */
 
-	EDestination *destination;
+	EDestination *destination = NULL;
+	gchar *name = NULL, *email = NULL;
 	const gchar *textrep;
-	gchar *name = NULL, *email = NULL, *tofree = NULL;
+	gchar *out;
+
+	g_return_if_fail (GTK_IS_TREE_MODEL (model));
 
 	gtk_tree_model_get (model, iter, 0, &destination, -1);
-	textrep = e_destination_get_textrep (destination, TRUE);
+	g_return_if_fail (destination && E_IS_DESTINATION (destination));
 
+	textrep = e_destination_get_textrep (destination, TRUE);
 	if (eab_parse_qp_email (textrep, &name, &email)) {
-		tofree = g_strdup_printf ("%s <%s>", name, email);
-		textrep = tofree;
-		g_free (name);
+		out = g_strdup_printf ("%s <%s>", name, email);
+		g_object_set (renderer, "text", out, NULL);
+		g_free (out);
 		g_free (email);
+		g_free (name);
+	} else {
+		g_object_set (renderer, "text", textrep, NULL);
 	}
 
-	g_object_set (renderer, "text", textrep, NULL);
 	g_object_unref (destination);
-	g_free (tofree);
-}
-
-static void
-contact_list_editor_row_deleted_cb (GtkTreeModel *model,
-                                    GtkTreePath *path,
-                                    EContactListEditor *editor)
-{
-	gint n_children;
-
-	n_children = gtk_tree_model_iter_n_children (model, NULL);
-	gtk_widget_set_sensitive (WIDGET (REMOVE_BUTTON), n_children > 0);
-}
-
-static void
-contact_list_editor_row_inserted_cb (GtkTreeModel *model,
-                                     GtkTreePath *path,
-                                     GtkTreeIter *iter,
-                                     EContactListEditor *editor)
-{
-	gtk_widget_set_sensitive (WIDGET (REMOVE_BUTTON), TRUE);
 }
 
 static void
@@ -387,9 +393,12 @@ contact_list_editor_selection_changed_cb (GtkTreeSelection *selection,
 		gtk_widget_set_sensitive (WIDGET (UP_BUTTON), FALSE);
 		gtk_widget_set_sensitive (WIDGET (DOWN_BUTTON), FALSE);
 		gtk_widget_set_sensitive (WIDGET (BOTTOM_BUTTON), FALSE);
+		gtk_widget_set_sensitive (WIDGET (REMOVE_BUTTON), FALSE);
 		return;
 	}
 
+	gtk_widget_set_sensitive (WIDGET (REMOVE_BUTTON), TRUE);
+
 	/* Item before selected item exists => enable Top/Up buttons */
 	selected = gtk_tree_selection_get_selected_rows (selection, &model);
 
@@ -430,7 +439,9 @@ contact_list_editor_add_button_clicked_cb (GtkWidget *widget)
 
 	editor = contact_list_editor_extract (widget);
 
-	contact_list_editor_add_email (editor);
+	contact_list_editor_add_email (editor,
+		gtk_entry_get_text (GTK_ENTRY (WIDGET (EMAIL_ENTRY))));
+	gtk_entry_set_text (GTK_ENTRY (WIDGET (EMAIL_ENTRY)), "");
 }
 
 void
@@ -502,7 +513,6 @@ contact_list_editor_drag_data_received_cb (GtkWidget *widget,
 {
 	CamelInternetAddress *address;
 	EContactListEditor *editor;
-	EContactListModel *model;
 	gboolean changed = FALSE;
 	gboolean handled = FALSE;
 	const guchar *data;
@@ -512,7 +522,6 @@ contact_list_editor_drag_data_received_cb (GtkWidget *widget,
 	gchar *text;
 
 	editor = contact_list_editor_extract (widget);
-	model = E_CONTACT_LIST_MODEL (editor->priv->model);
 
 	target = gtk_selection_data_get_target (selection_data);
 
@@ -532,24 +541,14 @@ contact_list_editor_drag_data_received_cb (GtkWidget *widget,
 
 	for (iter = list; iter != NULL; iter = iter->next) {
 		EContact *contact = iter->data;
-		const gchar *email;
+		EDestination *dest;
 
-		if (e_contact_get (contact, E_CONTACT_IS_LIST))
-			continue;
+		dest = e_destination_new ();
+		e_destination_set_contact (dest, contact, 0);
 
-		email = e_contact_get (contact, E_CONTACT_EMAIL_1);
-		if (email == NULL) {
-			g_warning (
-				"Contact with no email-ids listed "
-				"can't be added to a Contact-List");
-			continue;
-		}
+		changed = contact_list_editor_add_destination (widget, dest) || changed;
 
-		if (!contact_list_editor_contact_exists (model, email)) {
-			/* Hard-wired for default e-mail */
-			e_contact_list_model_add_contact (model, contact, 0);
-			changed = TRUE;
-		}
+		g_object_unref (dest);
 	}
 
 	e_client_util_free_object_slist (list);
@@ -583,7 +582,7 @@ handle_text:
 		g_free (text);
 
 		text = camel_address_format (CAMEL_ADDRESS (address));
-		e_contact_list_model_add_email (model, text);
+		contact_list_editor_add_email (editor, text);
 
 		contact_list_editor_scroll_to_end (editor);
 		editor->priv->changed = TRUE;
@@ -605,10 +604,13 @@ void
 contact_list_editor_email_entry_activate_cb (GtkWidget *widget)
 {
 	EContactListEditor *editor;
+	GtkEntry *entry;
 
 	editor = contact_list_editor_extract (widget);
+	entry = GTK_ENTRY (WIDGET (EMAIL_ENTRY));
 
-	contact_list_editor_add_email (editor);
+	contact_list_editor_add_email (editor, gtk_entry_get_text (entry));
+	gtk_entry_set_text (entry, "");
 }
 
 void
@@ -666,8 +668,7 @@ contact_list_editor_email_entry_key_press_event_cb (GtkWidget *widget,
 	}
 
 	if (can_comma || event->keyval == GDK_KEY_Return) {
-		g_signal_emit_by_name (widget, "activate", 0);
-		contact_list_editor_add_email (editor);
+		g_signal_emit_by_name (WIDGET (EMAIL_ENTRY), "activate", 0);
 
 		return TRUE;
 	}
@@ -676,40 +677,6 @@ contact_list_editor_email_entry_key_press_event_cb (GtkWidget *widget,
 }
 
 void
-contact_list_editor_email_entry_updated_cb (GtkWidget *widget,
-                                            EDestination *destination);
-
-void
-contact_list_editor_email_entry_updated_cb (GtkWidget *widget,
-                                            EDestination *destination)
-{
-	EContactListEditor *editor;
-	ENameSelectorEntry *entry;
-	EContactListModel *model;
-	EDestinationStore *store;
-	gchar *email;
-
-	editor = contact_list_editor_extract (widget);
-
-	entry = E_NAME_SELECTOR_ENTRY (widget);
-	model = E_CONTACT_LIST_MODEL (editor->priv->model);
-
-	email = g_strdup (e_destination_get_textrep (destination, TRUE));
-	store = e_name_selector_entry_peek_destination_store (entry);
-	e_destination_store_remove_destination (store, destination);
-	gtk_entry_set_text (GTK_ENTRY (WIDGET (EMAIL_ENTRY)), "");
-
-	if (email && *email) {
-		e_contact_list_model_add_email (model, email);
-		contact_list_editor_scroll_to_end (editor);
-		editor->priv->changed = TRUE;
-	}
-
-	g_free (email);
-	contact_list_editor_update (editor);
-}
-
-void
 contact_list_editor_list_name_entry_changed_cb (GtkWidget *widget);
 
 void
@@ -798,7 +765,7 @@ contact_list_editor_remove_button_clicked_cb (GtkWidget *widget)
 		gtk_tree_path_free (path);
 		g_assert (valid);
 
-		gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+		e_contact_list_model_remove_row (E_CONTACT_LIST_MODEL (model), &iter);
 		gtk_tree_row_reference_free (reference);
 	}
 
@@ -838,7 +805,6 @@ void
 contact_list_editor_select_button_clicked_cb (GtkWidget *widget)
 {
 	EContactListEditor *editor;
-	EContactListModel *model;
 	ENameSelectorDialog *dialog;
 	EDestinationStore *store;
 	GList *list, *iter;
@@ -846,7 +812,6 @@ contact_list_editor_select_button_clicked_cb (GtkWidget *widget)
 
 	editor = contact_list_editor_extract (widget);
 
-	model = E_CONTACT_LIST_MODEL (editor->priv->model);
 	dialog = e_name_selector_peek_dialog (editor->priv->name_selector);
 	gtk_window_set_title (GTK_WINDOW (dialog), _("Contact List Members"));
 
@@ -876,18 +841,14 @@ contact_list_editor_select_button_clicked_cb (GtkWidget *widget)
 
 	for (iter = list; iter != NULL; iter = iter->next) {
 		EDestination *destination = iter->data;
-		const gchar *email = e_destination_get_email (destination);
 
-		if (email == NULL)
-			continue;
-
-		if (!contact_list_editor_contact_exists (model, email))
-			e_contact_list_model_add_destination (
-				model, destination);
+		contact_list_editor_add_destination (widget, destination);
 	}
 
 	g_list_free (list);
 
+	gtk_entry_set_text (GTK_ENTRY (WIDGET (EMAIL_ENTRY)), "");
+
 	editor->priv->changed = TRUE;
 	contact_list_editor_update (editor);
 }
@@ -962,8 +923,8 @@ contact_list_editor_top_button_clicked_cb (GtkButton *button)
 	for (l = references; l; l = l->next) {
 		path = gtk_tree_row_reference_get_path (l->data);
 		gtk_tree_model_get_iter (model, &iter, path);
-		gtk_list_store_move_after (
-			GTK_LIST_STORE (model), &iter, NULL);
+		gtk_tree_store_move_after (
+			GTK_TREE_STORE (model), &iter, NULL);
 		gtk_tree_path_free (path);
 	}
 
@@ -1006,7 +967,7 @@ contact_list_editor_up_button_clicked_cb (GtkButton *button)
 	/* Get iter of the last selected item */
 	gtk_tree_model_get_iter (model, &iter2, g_list_last (selected)->data);
 
-	gtk_list_store_move_after (GTK_LIST_STORE (model), &iter, &iter2);
+	gtk_tree_store_move_after (GTK_TREE_STORE (model), &iter, &iter2);
 
 	g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
 	g_list_free (selected);
@@ -1042,7 +1003,7 @@ contact_list_editor_down_button_clicked_cb (GtkButton *button)
 	gtk_tree_model_get_iter (model, &iter2, g_list_last (selected)->data);
 	gtk_tree_model_iter_next (model, &iter2);
 
-	gtk_list_store_move_before (GTK_LIST_STORE (model), &iter2, &iter);
+	gtk_tree_store_move_before (GTK_TREE_STORE (model), &iter2, &iter);
 
 	g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
 	g_list_free (selected);
@@ -1082,8 +1043,8 @@ contact_list_editor_bottom_button_clicked_cb (GtkButton *button)
 	for (l = references; l; l = l->next) {
 		path = gtk_tree_row_reference_get_path (l->data);
 		gtk_tree_model_get_iter (model, &iter, path);
-		gtk_list_store_move_before (
-			GTK_LIST_STORE (model), &iter, NULL);
+		gtk_tree_store_move_before (
+			GTK_TREE_STORE (model), &iter, NULL);
 		gtk_tree_path_free (path);
 	}
 
@@ -1205,9 +1166,6 @@ setup_custom_widgets (EContactListEditor *editor)
 	g_signal_connect (
 		name_selector_entry, "key-press-event", G_CALLBACK (
 		contact_list_editor_email_entry_key_press_event_cb), NULL);
-	g_signal_connect (
-		name_selector_entry, "updated", G_CALLBACK (
-		contact_list_editor_email_entry_updated_cb), NULL);
 }
 
 /***************************** GObject Callbacks *****************************/
@@ -1314,6 +1272,16 @@ contact_list_editor_dispose (GObject *object)
 		priv->name_selector = NULL;
 	}
 
+	if (priv->contact) {
+		g_object_unref (priv->contact);
+		priv->contact = NULL;
+	}
+
+	if (priv->builder) {
+		g_object_unref (priv->builder);
+		priv->builder = NULL;
+	}
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -1561,13 +1529,6 @@ contact_list_editor_init (EContactListEditor *editor)
 	e_drag_dest_add_directory_targets (WIDGET (TREE_VIEW));
 	gtk_drag_dest_add_text_targets (WIDGET (TREE_VIEW));
 
-	g_signal_connect (
-		priv->model, "row-deleted",
-		G_CALLBACK (contact_list_editor_row_deleted_cb), editor);
-	g_signal_connect (
-		priv->model, "row-inserted",
-		G_CALLBACK (contact_list_editor_row_inserted_cb), editor);
-
 	column = gtk_tree_view_column_new ();
 	renderer = gtk_cell_renderer_text_new ();
 	g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
@@ -1666,15 +1627,63 @@ e_contact_list_editor_set_client (EContactListEditor *editor,
 	g_object_notify (G_OBJECT (editor), "client");
 }
 
+static void
+save_contact_list (GtkTreeModel *model, GtkTreeIter *iter, GSList **attrs, gint *parent_id)
+{
+	EDestination *dest;
+	EVCardAttribute *attr;
+	gchar *pid_str = g_strdup_printf ("%d", *parent_id);
+
+	do {
+		gtk_tree_model_get (model, iter, 0, &dest, -1);
+
+		if (gtk_tree_model_iter_has_child (model, iter)) {
+			GtkTreeIter new_iter;
+			gchar *uid;
+
+			(*parent_id)++;
+			uid = g_strdup_printf ("%d", *parent_id);
+
+			attr = e_vcard_attribute_new (NULL, EVC_CONTACT_LIST);
+			e_vcard_attribute_add_param_with_value (attr,
+				e_vcard_attribute_param_new (EVC_CL_UID), uid);
+			e_vcard_attribute_add_value (attr,
+				e_destination_get_name (dest));
+
+			g_free (uid);
+
+			/* Set new_iter to first child of iter */
+			gtk_tree_model_iter_children (model, &new_iter, iter);
+
+			/* Go recursive */
+			save_contact_list (model, &new_iter, attrs, parent_id);
+		} else {
+			attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
+			e_destination_export_to_vcard_attribute (dest, attr);
+		}
+
+		e_vcard_attribute_add_param_with_value (attr,
+			e_vcard_attribute_param_new (EVC_PARENT_CL), pid_str);
+
+
+		*attrs = g_slist_prepend (*attrs, attr);
+
+		g_object_unref (dest);
+
+	} while (gtk_tree_model_iter_next (model, iter));
+
+	g_free (pid_str);
+}
+
 EContact *
 e_contact_list_editor_get_contact (EContactListEditor *editor)
 {
 	GtkTreeModel *model;
 	EContact *contact;
 	GtkTreeIter iter;
-	gboolean iter_valid;
 	const gchar *text;
 	GSList *attrs = NULL, *a;
+	gint parent_id = 0;
 
 	g_return_val_if_fail (E_IS_CONTACT_LIST_EDITOR (editor), NULL);
 
@@ -1686,8 +1695,8 @@ e_contact_list_editor_get_contact (EContactListEditor *editor)
 
 	text = gtk_entry_get_text (GTK_ENTRY (WIDGET (LIST_NAME_ENTRY)));
 	if (text != NULL && *text != '\0') {
-		e_contact_set (contact, E_CONTACT_FILE_AS, (gpointer) text);
-		e_contact_set (contact, E_CONTACT_FULL_NAME, (gpointer) text);
+		e_contact_set (contact, E_CONTACT_FILE_AS, text);
+		e_contact_set (contact, E_CONTACT_FULL_NAME, text);
 	}
 
 	e_contact_set (contact, E_CONTACT_LOGO, NULL);
@@ -1699,21 +1708,10 @@ e_contact_list_editor_get_contact (EContactListEditor *editor)
 		GTK_TOGGLE_BUTTON (WIDGET (CHECK_BUTTON)))));
 
 	e_vcard_remove_attributes (E_VCARD (contact), "", EVC_EMAIL);
+	e_vcard_remove_attributes (E_VCARD (contact), "", EVC_CONTACT_LIST);
 
-	iter_valid = gtk_tree_model_get_iter_first (model, &iter);
-
-	while (iter_valid) {
-		EDestination *dest;
-		EVCardAttribute *attr;
-
-		gtk_tree_model_get (model, &iter, 0, &dest, -1);
-		attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
-		attrs = g_slist_prepend (attrs, attr);
-		e_destination_export_to_vcard_attribute (dest, attr);
-		g_object_unref (dest);
-
-		iter_valid = gtk_tree_model_iter_next (model, &iter);
-	}
+	if (gtk_tree_model_get_iter_first (model, &iter))
+		save_contact_list (model, &iter, &attrs, &parent_id);
 
 	/* Put it in reverse order because e_vcard_add_attribute also uses prepend,
 	   but we want to keep order of mails there. Hopefully noone will change
@@ -1722,59 +1720,9 @@ e_contact_list_editor_get_contact (EContactListEditor *editor)
 		e_vcard_add_attribute (E_VCARD (contact), a->data);
 	}
 
-	return contact;
-}
+	g_slist_free (attrs);
 
-/* Helper for e_contact_list_editor_set_contact() */
-static void
-contact_list_editor_add_destination (EVCardAttribute *attr,
-                                     EContactListEditor *editor)
-{
-	EDestination *destination;
-	gchar *contact_uid = NULL;
-	gint email_num = -1;
-	GList *list, *iter;
-	GList *values;
-	gchar *value;
-
-	destination = e_destination_new ();
-
-	list = e_vcard_attribute_get_params (attr);
-	for (iter = list; iter; iter = iter->next) {
-		EVCardAttributeParam *param = iter->data;
-		const gchar *param_name;
-		gpointer param_data;
-
-		values = e_vcard_attribute_param_get_values (param);
-		if (values == NULL)
-			continue;
-
-		param_name = e_vcard_attribute_param_get_name (param);
-		param_data = values->data;
-
-		if (!g_ascii_strcasecmp (param_name, EVC_X_DEST_CONTACT_UID))
-			contact_uid = param_data;
-		else if (!g_ascii_strcasecmp (param_name, EVC_X_DEST_EMAIL_NUM))
-			email_num = atoi (param_data);
-		else if (!g_ascii_strcasecmp (param_name, EVC_X_DEST_HTML_MAIL))
-			e_destination_set_html_mail_pref (
-				destination,
-				!g_ascii_strcasecmp (param_data, "true"));
-	}
-
-	value = e_vcard_attribute_get_value (attr);
-	if (value)
-		e_destination_set_raw (destination, value);
-	g_free (value);
-
-	if (contact_uid != NULL)
-		e_destination_set_contact_uid (
-			destination, contact_uid, email_num);
-
-	e_contact_list_model_add_destination (
-		E_CONTACT_LIST_MODEL (editor->priv->model), destination);
-
-	e_vcard_attribute_free (attr);
+	return contact;
 }
 
 void
@@ -1790,19 +1738,19 @@ e_contact_list_editor_set_contact (EContactListEditor *editor,
 
 	if (priv->contact != NULL)
 		g_object_unref (priv->contact);
+
 	priv->contact = e_contact_duplicate (contact);
 
 	if (priv->contact != NULL) {
 		const gchar *file_as;
 		gboolean show_addresses;
-		GList *email_list;
+		const GList *dests, *dest;
 
-		file_as = e_contact_get_const (
-			priv->contact, E_CONTACT_FILE_AS);
-		email_list = e_contact_get_attributes (
-			priv->contact, E_CONTACT_EMAIL);
-		show_addresses = GPOINTER_TO_INT (e_contact_get (
-			priv->contact, E_CONTACT_LIST_SHOW_ADDRESSES));
+		/* The root destination */
+		EDestination *list_dest = e_destination_new ();
+
+		file_as = e_contact_get_const (priv->contact, E_CONTACT_FILE_AS);
+		show_addresses = GPOINTER_TO_INT (e_contact_get (priv->contact, E_CONTACT_LIST_SHOW_ADDRESSES));
 
 		if (file_as == NULL)
 			file_as = "";
@@ -1817,10 +1765,19 @@ e_contact_list_editor_set_contact (EContactListEditor *editor,
 		e_contact_list_model_remove_all (
 			E_CONTACT_LIST_MODEL (priv->model));
 
-		g_list_foreach (
-			email_list, (GFunc)
-			contact_list_editor_add_destination, editor);
-		g_list_free (email_list);
+		e_destination_set_name (list_dest, file_as);
+		e_destination_set_contact (list_dest, priv->contact, 0);
+
+		dests = e_destination_list_get_root_dests (list_dest);
+		for (dest = dests; dest; dest = dest->next) {
+			GtkTreePath *path;
+			path = e_contact_list_model_add_destination (E_CONTACT_LIST_MODEL (priv->model), dest->data, NULL);
+			gtk_tree_path_free (path);
+		}
+
+		g_object_unref (list_dest);
+
+		gtk_tree_view_expand_all (GTK_TREE_VIEW (WIDGET (TREE_VIEW)));
 	}
 
 	if (priv->book_client != NULL) {
@@ -1835,6 +1792,7 @@ e_contact_list_editor_set_contact (EContactListEditor *editor,
 	contact_list_editor_update (editor);
 
 	g_object_notify (G_OBJECT (editor), "contact");
+
 }
 
 gboolean
diff --git a/addressbook/gui/contact-list-editor/e-contact-list-model.c b/addressbook/gui/contact-list-editor/e-contact-list-model.c
index 1a0cc6d..63e0f59 100644
--- a/addressbook/gui/contact-list-editor/e-contact-list-model.c
+++ b/addressbook/gui/contact-list-editor/e-contact-list-model.c
@@ -31,6 +31,15 @@
 
 static gpointer parent_class;
 
+G_DEFINE_TYPE (EContactListModel, e_contact_list_model, GTK_TYPE_TREE_STORE);
+
+struct _EContactListModelPrivate {
+
+	GHashTable *uids_table;
+	GHashTable *emails_table;
+
+};
+
 static gboolean
 contact_list_get_iter (EContactListModel *model,
                        GtkTreeIter *iter,
@@ -61,38 +70,51 @@ contact_list_model_constructor (GType type,
 	object = G_OBJECT_CLASS (parent_class)->constructor (
 		type, n_construct_properties, construct_properties);
 
-	gtk_list_store_set_column_types (
-		GTK_LIST_STORE (object), G_N_ELEMENTS (types), types);
+	gtk_tree_store_set_column_types (
+		GTK_TREE_STORE (object), G_N_ELEMENTS (types), types);
 
 	return object;
 }
 
 static void
-contact_list_model_class_init (EContactListModelClass *class)
+contact_list_model_dispose (GObject *object)
+{
+	EContactListModelPrivate *priv = E_CONTACT_LIST_MODEL (object)->priv;
+
+	if (priv->uids_table) {
+		g_hash_table_unref (priv->uids_table);
+		priv->uids_table = NULL;
+	}
+
+	if (priv->emails_table) {
+		g_hash_table_unref (priv->emails_table);
+		priv->emails_table = NULL;
+	}
+
+	G_OBJECT_CLASS (e_contact_list_model_parent_class)->dispose (object);
+}
+
+static void
+e_contact_list_model_class_init (EContactListModelClass *class)
 {
 	GObjectClass *object_class;
 
+	g_type_class_add_private (class, sizeof (EContactListModelPrivate));
+
 	parent_class = g_type_class_peek_parent (class);
 
 	object_class = G_OBJECT_CLASS (class);
 	object_class->constructor = contact_list_model_constructor;
+	object_class->dispose = contact_list_model_dispose;
 }
 
-GType
-e_contact_list_model_get_type (void)
+static void
+e_contact_list_model_init (EContactListModel *model)
 {
-	static GType type = 0;
-
-	if (G_UNLIKELY (type == 0))
-		type = g_type_register_static_simple (
-			GTK_TYPE_LIST_STORE,
-			"EContactListModel",
-			sizeof (EContactListModelClass),
-			(GClassInitFunc) contact_list_model_class_init,
-			sizeof (EContactListModel),
-			(GInstanceInitFunc) NULL, 0);
-
-	return type;
+	model->priv = G_TYPE_INSTANCE_GET_PRIVATE (model, E_TYPE_CONTACT_LIST_MODEL, EContactListModelPrivate);
+
+	model->priv->uids_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	model->priv->emails_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 }
 
 GtkTreeModel *
@@ -105,64 +127,51 @@ gboolean
 e_contact_list_model_has_email (EContactListModel *model,
                                 const gchar *email)
 {
-	GtkTreeIter iter;
-	gboolean iter_valid;
-	gboolean has_email = FALSE;
-
-	g_return_val_if_fail (E_IS_CONTACT_LIST_MODEL (model), FALSE);
-	g_return_val_if_fail (email != NULL, FALSE);
-
-	iter_valid = gtk_tree_model_get_iter_first (
-		GTK_TREE_MODEL (model), &iter);
-
-	while (!has_email && iter_valid) {
-		EDestination *destination;
-		const gchar *textrep;
-
-		gtk_tree_model_get (
-			GTK_TREE_MODEL (model), &iter, 0, &destination, -1);
-		textrep = e_destination_get_textrep (destination, TRUE);
-		has_email = (strcmp (email, textrep) == 0);
-		g_object_unref (destination);
-
-		iter_valid = gtk_tree_model_iter_next (
-			GTK_TREE_MODEL (model), &iter);
-	}
+	return (g_hash_table_lookup (model->priv->emails_table, email) != NULL);
+}
 
-	return has_email;
+gboolean
+e_contact_list_model_has_uid (EContactListModel *model,
+			      const gchar* uid)
+{
+	return (g_hash_table_lookup (model->priv->uids_table, uid) != NULL);
 }
 
-void
+GtkTreePath*
 e_contact_list_model_add_destination (EContactListModel *model,
-                                      EDestination *destination)
+                                      EDestination *destination,
+                                      GtkTreeIter *parent)
 {
 	GtkTreeIter iter;
+	GtkTreePath *path;
 
-	g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model));
-	g_return_if_fail (E_IS_DESTINATION (destination));
+	g_return_val_if_fail (E_IS_CONTACT_LIST_MODEL (model), NULL);
+	g_return_val_if_fail (E_IS_DESTINATION (destination), NULL);
 
-	gtk_list_store_append (GTK_LIST_STORE (model), &iter);
-	gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, destination, -1);
-}
+	gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent);
+	gtk_tree_store_set (GTK_TREE_STORE (model), &iter, 0, destination, -1);
 
-void
-e_contact_list_model_add_email (EContactListModel *model,
-                                const gchar *email)
-{
-	const gchar *tag = "addressbook:ask-list-add-exists";
-	EDestination *destination;
+	if (e_destination_is_evolution_list (destination)) {
+		const GList *dest, *dests = e_destination_list_get_root_dests (destination);
 
-	g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model));
-	g_return_if_fail (email != NULL);
+		g_hash_table_insert (model->priv->uids_table,
+			g_strdup (e_destination_get_contact_uid (destination)),
+			destination);
 
-	if (e_contact_list_model_has_email (model, email))
-		if (e_alert_run_dialog_for_args (e_shell_get_active_window
-						 (NULL), tag, email, NULL) != GTK_RESPONSE_YES)
-			return;
+		for (dest = dests; dest; dest = dest->next) {
+			path = e_contact_list_model_add_destination (model, dest->data, &iter);
+			if (dest->next)
+				gtk_tree_path_free (path);
+		}
+	} else {
+		g_hash_table_insert (model->priv->emails_table,
+			g_strdup (e_destination_get_email (destination)),
+			destination);
 
-	destination = e_destination_new ();
-	e_destination_set_email (destination, email);
-	e_contact_list_model_add_destination (model, destination);
+		path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+	}
+
+	return path;
 }
 
 void
@@ -177,22 +186,30 @@ e_contact_list_model_add_contact (EContactListModel *model,
 
 	destination = e_destination_new ();
 	e_destination_set_contact (destination, contact, email_num);
-	e_contact_list_model_add_destination (model, destination);
+	e_contact_list_model_add_destination (model, destination, NULL);
 }
 
 void
 e_contact_list_model_remove_row (EContactListModel *model,
-                                 gint row)
+                                 GtkTreeIter *iter)
 {
-	GtkTreeIter iter;
-	gboolean iter_valid;
+	EDestination *dest;
 
 	g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model));
+	g_return_if_fail (iter);
 
-	iter_valid = contact_list_get_iter (model, &iter, row);
-	g_return_if_fail (iter_valid);
+	gtk_tree_model_get (GTK_TREE_MODEL (model), iter, 0, &dest, -1);
 
-	gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+	if (e_destination_is_evolution_list (dest)) {
+		const gchar *uid = e_destination_get_contact_uid (dest);
+		g_hash_table_remove (model->priv->uids_table, uid);
+	} else {
+		const gchar *email = e_destination_get_email (dest);
+		g_hash_table_remove (model->priv->emails_table, email);
+	}
+
+	g_object_unref (dest);
+	gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
 }
 
 void
@@ -200,7 +217,10 @@ e_contact_list_model_remove_all (EContactListModel *model)
 {
 	g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model));
 
-	gtk_list_store_clear (GTK_LIST_STORE (model));
+	g_hash_table_remove_all (model->priv->uids_table);
+	g_hash_table_remove_all (model->priv->emails_table);
+
+	gtk_tree_store_clear (GTK_TREE_STORE (model));
 }
 
 EDestination *
diff --git a/addressbook/gui/contact-list-editor/e-contact-list-model.h b/addressbook/gui/contact-list-editor/e-contact-list-model.h
index 43d3288..b902658 100644
--- a/addressbook/gui/contact-list-editor/e-contact-list-model.h
+++ b/addressbook/gui/contact-list-editor/e-contact-list-model.h
@@ -46,30 +46,35 @@
 G_BEGIN_DECLS
 
 typedef struct _EContactListModel EContactListModel;
+typedef struct _EContactListModelPrivate EContactListModelPrivate;
 typedef struct _EContactListModelClass EContactListModelClass;
 
 struct _EContactListModel {
-	GtkListStore parent;
+	GtkTreeStore parent;
+	EContactListModelPrivate *priv;
 };
 
 struct _EContactListModelClass {
-	GtkListStoreClass parent_class;
+	GtkTreeStoreClass parent_class;
 };
 
 GType		e_contact_list_model_get_type	(void);
 GtkTreeModel *	e_contact_list_model_new	(void);
 gboolean	e_contact_list_model_has_email	(EContactListModel *model,
 						 const gchar *email);
-void		e_contact_list_model_add_destination
+
+gboolean	e_contact_list_model_has_uid	(EContactListModel *model,
+						 const gchar *uid);
+
+GtkTreePath *	e_contact_list_model_add_destination
 						(EContactListModel *model,
-						 EDestination *dest);
-void		e_contact_list_model_add_email	(EContactListModel *model,
-						 const gchar *email);
+						 EDestination *dest,
+						 GtkTreeIter *parent);
 void		e_contact_list_model_add_contact (EContactListModel *model,
 						 EContact *contact,
 						 gint email_num);
 void		e_contact_list_model_remove_row	(EContactListModel *model,
-						 gint row);
+						 GtkTreeIter *iter);
 void		e_contact_list_model_remove_all	(EContactListModel *model);
 EDestination *	e_contact_list_model_get_destination
 						(EContactListModel *model,
diff --git a/addressbook/gui/widgets/Makefile.am b/addressbook/gui/widgets/Makefile.am
index 64777ee..40c5765 100644
--- a/addressbook/gui/widgets/Makefile.am
+++ b/addressbook/gui/widgets/Makefile.am
@@ -9,6 +9,7 @@ libeabwidgets_la_CPPFLAGS =				\
 	-DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\"	\
 	-DEVOLUTION_GALVIEWSDIR=\""$(viewsdir)"\"	\
 	-DEVOLUTION_RULEDIR=\"$(ruledir)\"		\
+	-DEVOLUTION_IMAGESDIR=\"${imagesdir}\"		\
 	-I$(top_srcdir)					\
 	-I$(top_srcdir)/filter				\
 	-I$(top_srcdir)/widgets				\
@@ -69,6 +70,7 @@ libeabwidgets_la_LIBADD =					\
 	$(top_builddir)/widgets/table/libetable.la		\
 	$(top_builddir)/widgets/menus/libmenus.la		\
 	$(top_builddir)/a11y/libevolution-a11y.la		\
+	$(top_builddir)/e-util/libeutil.la			\
 	$(GNOME_PLATFORM_LIBS)					\
 	$(CHAMPLAIN_LIBS)
 
diff --git a/addressbook/gui/widgets/eab-contact-display.c b/addressbook/gui/widgets/eab-contact-display.c
index c3d8fb7..ab66e8d 100644
--- a/addressbook/gui/widgets/eab-contact-display.c
+++ b/addressbook/gui/widgets/eab-contact-display.c
@@ -28,6 +28,7 @@
 
 #include "eab-gui-util.h"
 #include "e-util/e-util.h"
+#include "e-util/e-util-private.h"
 #include "e-util/e-html-utils.h"
 #include "e-util/e-icon-factory.h"
 #include "e-util/e-plugin-ui.h"
@@ -50,6 +51,8 @@ struct _EABContactDisplayPrivate {
 	EABContactDisplayMode mode;
 	GtkOrientation orientation;
 	gboolean show_maps;
+
+	GHashTable *closed_lists; /* see render_contact_list_* */
 };
 
 enum {
@@ -409,7 +412,7 @@ render_title_block (GString *buffer, EContact *contact)
 
 	g_string_append_printf (
 			buffer, "<table border=\"0\"><tr>"
-			"<td %s valign=\"top\">", TEXT_IS_RIGHT_TO_LEFT ?
+			"<td %s valign=\"middle\">", TEXT_IS_RIGHT_TO_LEFT ?
 			"align=\"right\"" : "");
 	photo = e_contact_get (contact, E_CONTACT_PHOTO);
 	if (!photo)
@@ -421,6 +424,9 @@ render_title_block (GString *buffer, EContact *contact)
 	if (photo)
 		e_contact_photo_free (photo);
 
+	if (e_contact_get (contact, E_CONTACT_IS_LIST))
+		g_string_append (buffer, "<img src=\"evo-icon:" CONTACT_LIST_ICON "\">");
+
 	g_string_append_printf (
 		buffer, "</td><td width=\"20\"></td><td %s valign=\"top\">\n",
 		TEXT_IS_RIGHT_TO_LEFT ? "align=\"right\"" : "");
@@ -443,43 +449,126 @@ render_title_block (GString *buffer, EContact *contact)
 }
 
 static void
-render_contact_list (GString *buffer,
-                     EContact *contact)
+render_contact_list_row (GString *buffer,
+			 EDestination *destination,
+			 EABContactDisplay *display)
+ {
+	gchar *evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
+	gboolean list_collapsed = FALSE;
+	const gchar *listId = e_destination_get_contact_uid (destination), *textrep;
+	gchar *name = NULL, *email_addr = NULL;
+
+	if (listId)
+		list_collapsed = GPOINTER_TO_INT (g_hash_table_lookup (display->priv->closed_lists, listId));
+
+	textrep = e_destination_get_textrep (destination, TRUE);
+	if (!eab_parse_qp_email (textrep, &name, &email_addr))
+		email_addr = g_strdup (textrep);
+
+	g_string_append (buffer, "<tr>");
+	if (e_destination_is_evolution_list (destination)) {
+		g_string_append_printf (buffer,
+			"<td width=" IMAGE_COL_WIDTH " valign=\"top\"><a href=\"##%s##\"><img src=\"%s/%s.png\"></a></td><td width=\"100%%\">%s",
+			e_destination_get_contact_uid (destination),
+			evolution_imagesdir,
+			(list_collapsed ? "plus" : "minus"),
+			name ? name : email_addr);
+
+		if (!list_collapsed) {
+			const GList *dest, *dests;
+			g_string_append (buffer, "<br><table cellspacing=\"1\">");
+
+			dests = e_destination_list_get_root_dests (destination);
+			for (dest = dests; dest; dest = dest->next) {
+				render_contact_list_row (buffer, dest->data, display);
+			}
+
+			g_string_append (buffer, "</table>");
+		}
+
+		g_string_append (buffer, "</td>");
+
+	} else {
+		if (name && *name) {
+			g_string_append_printf (buffer, "<td colspan=\"2\">%s &lt<a href=\"mailto:%s\";>%s</a>&gt;</td>", name, email_addr, email_addr);
+		} else {
+			g_string_append_printf (buffer, "<td colspan=\"2\"><a href=\"mailto:%s\";>%s</a></td>", email_addr, email_addr);
+		}
+	}
+
+	g_string_append (buffer, "</tr>");
+
+	g_free (evolution_imagesdir);
+	g_free (name);
+	g_free (email_addr);
+}
+
+static void
+render_contact_list_vertical (GString *buffer,
+		              EContact *contact,
+        		      EABContactDisplay *display)
 {
-	GList *email_list;
-	GList *l;
+	EDestination *destination;
+	const GList *dest, *dests;
+
+	destination = e_destination_new ();
+	e_destination_set_contact (destination, contact, 0);
+	dests = e_destination_list_get_root_dests (destination);
 
 	render_title_block (buffer, contact);
 
-	g_string_append (
-		buffer, "<br><table border=\"0\" cellspacing=\"0\" "
-		"cellpadding=\"0\"><tr>");
-	g_string_append (
-		buffer, "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">");
-	g_string_append (
-		buffer, "<img width=\"16\" height=\"16\" "
-		"src=\"evo-icon:" CONTACT_LIST_ICON "\">");
-	g_string_append_printf (
-		buffer, "</td><td valign=\"top\" width=\"100\" nowrap>"
-		"<font color=" HEADER_COLOR ">%s:</font></td> "
-		"<td valign=\"top\">", _("List Members"));
+	g_string_append_printf (buffer, "<table border=\"0\"><tr><td valign=\"top\"><font color=" HEADER_COLOR ">%s</font></td><td>",
+		_("List Members:"));
+	g_string_append (buffer, "<table border=\"0\" cellspacing=\"1\">");
 
-	email_list = e_contact_get (contact, E_CONTACT_EMAIL);
-	for (l = email_list; l; l = l->next) {
-		gchar *value;
+	for (dest = dests; dest; dest = dest->next) {
+		render_contact_list_row (buffer, dest->data, display);
+ 	}
+
+	g_string_append (buffer, "</table>");
+	g_string_append (buffer, "</td></tr></table>");
+
+	g_object_unref (destination);
+}
 
-		value = eab_parse_qp_email_to_html (l->data);
+static void
+render_contact_list_horizontal (GString *buffer,
+		                EContact *contact,
+        		        EABContactDisplay *display)
+{
+	EDestination *destination;
+	const GList *dest, *dests;
+
+	destination = e_destination_new ();
+	e_destination_set_contact (destination, contact, 0);
+	dests = e_destination_list_get_root_dests (destination);
 
-		if (!value)
-			value = e_text_to_html (l->data, E_TEXT_TO_HTML_CONVERT_ADDRESSES);
+	render_title_block (buffer, contact);
 
-		g_string_append_printf (buffer, "%s<br>", value);
+	g_string_append_printf (buffer, "<table border=\"0\"><tr><td colspan=\"2\" valign=\"top\"><font color=" HEADER_COLOR ">%s</font></td></tr>"
+		"<tr><td with=" IMAGE_COL_WIDTH "></td><td>", _("List Members:"));
+	g_string_append (buffer, "<table border=\"0\" cellspacing=\"1\">");
 
-		g_free (value);
-	}
+	for (dest = dests; dest; dest = dest->next) {
+		render_contact_list_row (buffer, dest->data, display);
+ 	}
 
+	g_string_append (buffer, "</table>");
 	g_string_append (buffer, "</td></tr></table>");
-	g_list_free (email_list);
+
+	g_object_unref (destination);
+}
+
+static void
+render_contact_list (GString *buffer,
+                     EContact *contact,
+		     EABContactDisplay *display)
+
+{
+	if (display->priv->orientation == GTK_ORIENTATION_VERTICAL)
+		render_contact_list_vertical (buffer, contact, display);
+	else
+		render_contact_list_horizontal (buffer, contact, display);
 }
 
 static void
@@ -751,7 +840,7 @@ eab_contact_display_render_normal (EABContactDisplay *display,
 		orientation = display->priv->orientation;
 
 		if (e_contact_get (contact, E_CONTACT_IS_LIST))
-			render_contact_list (buffer, contact);
+			render_contact_list (buffer, contact, display);
 		else
 			render_contact (buffer, contact, orientation, display->priv->show_maps);
 
@@ -1035,6 +1124,11 @@ contact_display_dispose (GObject *object)
 		priv->contact = NULL;
 	}
 
+	if (priv->closed_lists != NULL) {
+		g_hash_table_unref (priv->closed_lists);
+		priv->closed_lists = NULL;
+	}
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -1160,6 +1254,19 @@ contact_display_link_clicked (EWebView *web_view,
 		index = atoi (uri + length);
 		contact_display_emit_send_message (display, index);
 		return;
+	} else if (g_str_has_prefix (uri, "##") && g_str_has_suffix (uri, "##")) {
+		gchar *list_id = g_strndup (uri+2, strlen (uri) - 4);
+
+		if (g_hash_table_lookup (display->priv->closed_lists, list_id)) {
+			g_hash_table_remove (display->priv->closed_lists, list_id);
+			g_free (list_id);
+		} else {
+			g_hash_table_insert (display->priv->closed_lists, list_id, GINT_TO_POINTER (TRUE));
+		}
+
+		eab_contact_display_render_normal (display, display->priv->contact);
+
+		return;
 	}
 
 	/* Chain up to parent's link_clicked() method. */
@@ -1338,6 +1445,8 @@ eab_contact_display_init (EABContactDisplay *display)
 	display->priv->mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
 	display->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
 	display->priv->show_maps = FALSE;
+	display->priv->closed_lists = g_hash_table_new_full (g_str_hash, g_str_equal,
+					(GDestroyNotify) g_free, NULL);
 
 	web_view = E_WEB_VIEW (display);
 	ui_manager = e_web_view_get_ui_manager (web_view);



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