evolution-3.6.4/addressbook/gui/contact-list-editor/e-contact-list-editor.c

No issues found

   1 /*
   2  * This program is free software; you can redistribute it and/or
   3  * modify it under the terms of the GNU Lesser General Public
   4  * License as published by the Free Software Foundation; either
   5  * version 2 of the License, or (at your option) version 3.
   6  *
   7  * This program is distributed in the hope that it will be useful,
   8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10  * Lesser General Public License for more details.
  11  *
  12  * You should have received a copy of the GNU Lesser General Public
  13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  14  *
  15  *
  16  * Authors:
  17  *		Chris Toshok <toshok@ximian.com>
  18  *
  19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  20  *
  21  */
  22 
  23 #ifdef HAVE_CONFIG_H
  24 #include <config.h>
  25 #endif
  26 
  27 #include "e-contact-list-editor.h"
  28 #include <e-util/e-util-private.h>
  29 #include <libevolution-utils/e-alert-dialog.h>
  30 #include <e-util/e-selection.h>
  31 #include "shell/e-shell.h"
  32 
  33 #include <string.h>
  34 
  35 #include <gtk/gtk.h>
  36 #include <glib/gi18n.h>
  37 #include <gdk/gdkkeysyms.h>
  38 
  39 #include <camel/camel.h>
  40 
  41 #include "e-util/e-util.h"
  42 #include "addressbook/gui/widgets/eab-gui-util.h"
  43 #include "addressbook/util/eab-book-util.h"
  44 
  45 #include "eab-editor.h"
  46 #include "e-contact-editor.h"
  47 #include "e-contact-list-model.h"
  48 #include "eab-contact-merging.h"
  49 
  50 #define E_CONTACT_LIST_EDITOR_GET_PRIVATE(obj) \
  51 	(G_TYPE_INSTANCE_GET_PRIVATE \
  52 	((obj), E_TYPE_CONTACT_LIST_EDITOR, EContactListEditorPrivate))
  53 
  54 #define E_CONTACT_LIST_EDITOR_GET_PRIVATE(obj) \
  55 	(G_TYPE_INSTANCE_GET_PRIVATE \
  56 	((obj), E_TYPE_CONTACT_LIST_EDITOR, EContactListEditorPrivate))
  57 
  58 #define CONTACT_LIST_EDITOR_WIDGET(editor, name) \
  59 	(e_builder_get_widget \
  60 	(E_CONTACT_LIST_EDITOR_GET_PRIVATE (editor)->builder, name))
  61 
  62 /* More macros, less typos. */
  63 #define CONTACT_LIST_EDITOR_WIDGET_ADD_BUTTON(editor) \
  64 	CONTACT_LIST_EDITOR_WIDGET ((editor), "add-button")
  65 #define CONTACT_LIST_EDITOR_WIDGET_CHECK_BUTTON(editor) \
  66 	CONTACT_LIST_EDITOR_WIDGET ((editor), "check-button")
  67 #define CONTACT_LIST_EDITOR_WIDGET_DIALOG(editor) \
  68 	CONTACT_LIST_EDITOR_WIDGET ((editor), "dialog")
  69 #define CONTACT_LIST_EDITOR_WIDGET_EMAIL_ENTRY(editor) \
  70 	E_CONTACT_LIST_EDITOR_GET_PRIVATE (editor)->email_entry
  71 #define CONTACT_LIST_EDITOR_WIDGET_LIST_NAME_ENTRY(editor) \
  72 	CONTACT_LIST_EDITOR_WIDGET ((editor), "list-name-entry")
  73 #define CONTACT_LIST_EDITOR_WIDGET_MEMBERS_VBOX(editor) \
  74 	CONTACT_LIST_EDITOR_WIDGET ((editor), "members-vbox")
  75 #define CONTACT_LIST_EDITOR_WIDGET_OK_BUTTON(editor) \
  76 	CONTACT_LIST_EDITOR_WIDGET ((editor), "ok-button")
  77 #define CONTACT_LIST_EDITOR_WIDGET_REMOVE_BUTTON(editor) \
  78 	CONTACT_LIST_EDITOR_WIDGET ((editor), "remove-button")
  79 #define CONTACT_LIST_EDITOR_WIDGET_SOURCE_MENU(editor) \
  80 	CONTACT_LIST_EDITOR_WIDGET ((editor), "source-combo-box")
  81 #define CONTACT_LIST_EDITOR_WIDGET_TREE_VIEW(editor) \
  82 	CONTACT_LIST_EDITOR_WIDGET ((editor), "tree-view")
  83 #define CONTACT_LIST_EDITOR_WIDGET_TOP_BUTTON(editor) \
  84 	CONTACT_LIST_EDITOR_WIDGET ((editor), "top-button")
  85 #define CONTACT_LIST_EDITOR_WIDGET_UP_BUTTON(editor) \
  86 	CONTACT_LIST_EDITOR_WIDGET ((editor), "up-button")
  87 #define CONTACT_LIST_EDITOR_WIDGET_DOWN_BUTTON(editor) \
  88 	CONTACT_LIST_EDITOR_WIDGET ((editor), "down-button")
  89 #define CONTACT_LIST_EDITOR_WIDGET_BOTTOM_BUTTON(editor) \
  90 	CONTACT_LIST_EDITOR_WIDGET ((editor), "bottom-button")
  91 
  92 /* Shorthand, requires a variable named "editor". */
  93 #define WIDGET(name)	(CONTACT_LIST_EDITOR_WIDGET_##name (editor))
  94 
  95 #define TOPLEVEL_KEY	(g_type_name (E_TYPE_CONTACT_LIST_EDITOR))
  96 
  97 enum {
  98 	PROP_0,
  99 	PROP_CLIENT,
 100 	PROP_CONTACT,
 101 	PROP_IS_NEW_LIST,
 102 	PROP_EDITABLE
 103 };
 104 
 105 typedef struct {
 106 	EContactListEditor *editor;
 107 	gboolean should_close;
 108 } EditorCloseStruct;
 109 
 110 struct _EContactListEditorPrivate {
 111 
 112 	EBookClient *book_client;
 113 	EContact *contact;
 114 
 115 	GtkBuilder *builder;
 116 	GtkTreeModel *model;
 117 	ENameSelector *name_selector;
 118 
 119 	/* This is kept here because the builder has an old widget
 120 	 * which was changed with this one. */
 121 	ENameSelectorEntry *email_entry;
 122 
 123 	/* Whether we are editing a new contact or an existing one. */
 124 	guint is_new_list : 1;
 125 
 126 	/* Whether the contact has been changed since bringing up the
 127 	 * contact editor. */
 128 	guint changed : 1;
 129 
 130 	/* Whether the contact editor will accept modifications. */
 131 	guint editable : 1;
 132 
 133 	/* Whether the target book accepts storing of contact lists. */
 134 	guint allows_contact_lists : 1;
 135 
 136 	/* Whether an async wombat call is in progress. */
 137 	guint in_async_call : 1;
 138 };
 139 
 140 G_DEFINE_TYPE (EContactListEditor, e_contact_list_editor, EAB_TYPE_EDITOR)
 141 
 142 static EContactListEditor *
 143 contact_list_editor_extract (GtkWidget *widget)
 144 {
 145 	GtkWidget *toplevel;
 146 
 147 	toplevel = gtk_widget_get_toplevel (widget);
 148 	return g_object_get_data (G_OBJECT (toplevel), TOPLEVEL_KEY);
 149 }
 150 
 151 static void
 152 contact_list_editor_scroll_to_end (EContactListEditor *editor)
 153 {
 154 	GtkTreeView *view;
 155 	GtkTreePath *path;
 156 	gint n_rows;
 157 
 158 	view = GTK_TREE_VIEW (WIDGET (TREE_VIEW));
 159 	n_rows = gtk_tree_model_iter_n_children (editor->priv->model, NULL);
 160 
 161 	path = gtk_tree_path_new_from_indices (n_rows - 1, -1);
 162 	gtk_tree_view_scroll_to_cell (view, path, NULL, FALSE, 0., 0.);
 163 	gtk_tree_view_set_cursor (view, path, NULL, FALSE);
 164 	gtk_tree_path_free (path);
 165 }
 166 
 167 static void
 168 contact_list_editor_update (EContactListEditor *editor)
 169 {
 170 	EContactListEditorPrivate *priv = editor->priv;
 171 
 172 	gtk_widget_set_sensitive (
 173 		WIDGET (OK_BUTTON),
 174 		eab_editor_is_valid (EAB_EDITOR (editor)) &&
 175 		priv->allows_contact_lists);
 176 
 177 	gtk_widget_set_sensitive (
 178 		WIDGET (SOURCE_MENU), priv->is_new_list);
 179 }
 180 
 181 static void
 182 contact_list_editor_notify_cb (EContactListEditor *editor,
 183                                GParamSpec *pspec)
 184 {
 185 	EContactListEditorPrivate *priv = editor->priv;
 186 	gboolean sensitive;
 187 
 188 	sensitive = priv->editable && priv->allows_contact_lists;
 189 
 190 	gtk_widget_set_sensitive (WIDGET (LIST_NAME_ENTRY), sensitive);
 191 	gtk_widget_set_sensitive (WIDGET (MEMBERS_VBOX), sensitive);
 192 }
 193 
 194 static gboolean
 195 contact_list_editor_add_destination (GtkWidget *widget,
 196                                      EDestination *dest)
 197 {
 198 	EContactListEditor *editor = contact_list_editor_extract (widget);
 199 	EContactListModel *model = E_CONTACT_LIST_MODEL (editor->priv->model);
 200 	GtkTreeView *treeview = GTK_TREE_VIEW (WIDGET (TREE_VIEW));
 201 	GtkTreePath *path;
 202 	gboolean ignore_conflicts = TRUE;
 203 
 204 	if (e_destination_is_evolution_list (dest)) {
 205 		const gchar *id = e_destination_get_contact_uid (dest);
 206 		const gchar *name = e_destination_get_name (dest);
 207 
 208 		if (e_contact_list_model_has_uid (model, id)) {
 209 			gint response;
 210 
 211 			response = e_alert_run_dialog_for_args (
 212 				GTK_WINDOW (WIDGET (DIALOG)),
 213 				"addressbook:ask-list-add-list-exists",
 214 				name, NULL);
 215 			if (response != GTK_RESPONSE_YES)
 216 				return FALSE;
 217 		} else {
 218 			const GList *l_dests, *l_dest;
 219 			gint reply;
 220 
 221 			/* Check the new list mail-by-mail for conflicts and
 222 			 * eventually ask user what to do with all conflicts. */
 223 			l_dests = e_destination_list_get_dests (dest);
 224 			for (l_dest = l_dests; l_dest; l_dest = l_dest->next) {
 225 				if (e_contact_list_model_has_email (model, e_destination_get_email (l_dest->data))) {
 226 					reply = e_alert_run_dialog_for_args (
 227 						GTK_WINDOW (WIDGET (DIALOG)),
 228 						"addressbook:ask-list-add-some-mails-exist", NULL);
 229 					if (reply == GTK_RESPONSE_YES) {
 230 						ignore_conflicts = TRUE;
 231 						break;
 232 					} else if (reply == GTK_RESPONSE_NO) {
 233 						ignore_conflicts = FALSE;
 234 						break;
 235 					} else {
 236 						return FALSE;
 237 					}
 238 				}
 239 			}
 240 		}
 241 
 242 	} else {
 243 		const gchar *email = e_destination_get_email (dest);
 244 		const gchar *tag = "addressbook:ask-list-add-exists";
 245 
 246 		if (e_contact_list_model_has_email (model, email) &&
 247 		    (e_alert_run_dialog_for_args (GTK_WINDOW (WIDGET (DIALOG)), tag, email, NULL) != GTK_RESPONSE_YES))
 248 			return FALSE;
 249 	}
 250 
 251 	/* always add to the root level */
 252 	path = e_contact_list_model_add_destination (
 253 		model, dest, NULL, ignore_conflicts);
 254 	if (path) {
 255 		contact_list_editor_scroll_to_end (editor);
 256 		gtk_tree_view_expand_to_path (treeview, path);
 257 		gtk_tree_path_free (path);
 258 
 259 		return TRUE;
 260 	}
 261 
 262 	return FALSE;
 263 }
 264 
 265 static void
 266 contact_list_editor_add_email (EContactListEditor *editor,
 267                                const gchar *email)
 268 {
 269 	CamelInternetAddress *addr;
 270 	EContactListEditorPrivate *priv = editor->priv;
 271 	EDestination *dest = NULL;
 272 	gint addr_length;
 273 
 274 	addr = camel_internet_address_new ();
 275 	addr_length = camel_address_unformat (CAMEL_ADDRESS (addr), email);
 276 	if (addr_length >= 1) {
 277 		const gchar *name, *mail;
 278 		gint ii;
 279 
 280 		for (ii = 0; ii < addr_length; ii++) {
 281 			camel_internet_address_get (addr, ii, &name, &mail);
 282 
 283 			if (name || mail) {
 284 				dest = e_destination_new ();
 285 				if (mail)
 286 					e_destination_set_email (dest, mail);
 287 				if (name)
 288 					e_destination_set_name (dest, name);
 289 
 290 				priv->changed = contact_list_editor_add_destination (WIDGET (DIALOG), dest)
 291 						|| priv->changed;
 292 			}
 293 		}
 294 	} else {
 295 		dest = e_destination_new ();
 296 		e_destination_set_email (dest, email);
 297 
 298 		priv->changed = contact_list_editor_add_destination (WIDGET (DIALOG), dest)
 299 				|| priv->changed;
 300 	}
 301 	g_object_unref (addr);
 302 
 303 	contact_list_editor_update (editor);
 304 }
 305 
 306 static void
 307 contact_list_editor_book_loaded_cb (GObject *source_object,
 308                                     GAsyncResult *result,
 309                                     gpointer user_data)
 310 {
 311 	ESource *source = E_SOURCE (source_object);
 312 	EContactListEditor *editor = user_data;
 313 	EContactListEditorPrivate *priv = editor->priv;
 314 	EContactStore *contact_store;
 315 	ENameSelectorEntry *entry;
 316 	EClient *client = NULL;
 317 	EBookClient *book_client;
 318 	GError *error = NULL;
 319 
 320 	e_client_utils_open_new_finish (source, result, &client, &error);
 321 
 322 	if (error != NULL) {
 323 		GtkWindow *parent;
 324 
 325 		g_warn_if_fail (client == NULL);
 326 
 327 		parent = eab_editor_get_window (EAB_EDITOR (editor));
 328 		eab_load_error_dialog (GTK_WIDGET (parent), NULL, source, error);
 329 
 330 		e_source_combo_box_set_active (
 331 			E_SOURCE_COMBO_BOX (WIDGET (SOURCE_MENU)),
 332 			e_client_get_source (E_CLIENT (priv->book_client)));
 333 
 334 		g_error_free (error);
 335 		goto exit;
 336 	}
 337 
 338 	g_return_if_fail (E_IS_CLIENT (client));
 339 
 340 	book_client = E_BOOK_CLIENT (client);
 341 
 342 	entry = E_NAME_SELECTOR_ENTRY (WIDGET (EMAIL_ENTRY));
 343 	contact_store = e_name_selector_entry_peek_contact_store (entry);
 344 	e_contact_store_add_client (contact_store, book_client);
 345 	e_contact_list_editor_set_client (editor, book_client);
 346 
 347 	g_object_unref (client);
 348 
 349 exit:
 350 	g_object_unref (editor);
 351 }
 352 
 353 static void
 354 contact_list_editor_list_added_cb (EBookClient *book_client,
 355                                    const GError *error,
 356                                    const gchar *id,
 357                                    gpointer closure)
 358 {
 359 	EditorCloseStruct *ecs = closure;
 360 	EContactListEditor *editor = ecs->editor;
 361 	EContactListEditorPrivate *priv = editor->priv;
 362 	gboolean should_close = ecs->should_close;
 363 
 364 	gtk_widget_set_sensitive (WIDGET (DIALOG), TRUE);
 365 	priv->in_async_call = FALSE;
 366 
 367 	e_contact_set (priv->contact, E_CONTACT_UID, (gchar *) id);
 368 
 369 	eab_editor_contact_added (
 370 		EAB_EDITOR (editor), error, priv->contact);
 371 
 372 	if (!error) {
 373 		priv->is_new_list = FALSE;
 374 
 375 		if (should_close)
 376 			eab_editor_close (EAB_EDITOR (editor));
 377 		else
 378 			contact_list_editor_update (editor);
 379 	}
 380 
 381 	g_object_unref (editor);
 382 	g_free (ecs);
 383 }
 384 
 385 static void
 386 contact_list_editor_list_modified_cb (EBookClient *book_client,
 387                                       const GError *error,
 388                                       gpointer closure)
 389 {
 390 	EditorCloseStruct *ecs = closure;
 391 	EContactListEditor *editor = ecs->editor;
 392 	EContactListEditorPrivate *priv = editor->priv;
 393 	gboolean should_close = ecs->should_close;
 394 
 395 	gtk_widget_set_sensitive (WIDGET (DIALOG), TRUE);
 396 	priv->in_async_call = FALSE;
 397 
 398 	eab_editor_contact_modified (
 399 		EAB_EDITOR (editor), error, priv->contact);
 400 
 401 	if (!error) {
 402 		if (should_close)
 403 			eab_editor_close (EAB_EDITOR (editor));
 404 	}
 405 
 406 	g_object_unref (editor);
 407 	g_free (ecs);
 408 }
 409 
 410 static void
 411 contact_list_editor_render_destination (GtkTreeViewColumn *column,
 412                                         GtkCellRenderer *renderer,
 413                                         GtkTreeModel *model,
 414                                         GtkTreeIter *iter)
 415 {
 416 	/* XXX Would be nice if EDestination had a text property
 417 	 *     that we could just bind the GtkCellRenderer to. */
 418 
 419 	EDestination *destination = NULL;
 420 	gchar *name = NULL, *email = NULL;
 421 	const gchar *textrep;
 422 	gchar *out;
 423 
 424 	g_return_if_fail (GTK_IS_TREE_MODEL (model));
 425 
 426 	gtk_tree_model_get (model, iter, 0, &destination, -1);
 427 	g_return_if_fail (destination && E_IS_DESTINATION (destination));
 428 
 429 	textrep = e_destination_get_textrep (destination, TRUE);
 430 	if (eab_parse_qp_email (textrep, &name, &email)) {
 431 		if (e_destination_is_evolution_list (destination)) {
 432 			g_object_set (renderer, "text", name, NULL);
 433 		} else {
 434 			out = g_strdup_printf ("%s <%s>", name, email);
 435 			g_object_set (renderer, "text", out, NULL);
 436 			g_free (out);
 437 		}
 438 		g_free (email);
 439 		g_free (name);
 440 	} else {
 441 		g_object_set (renderer, "text", textrep, NULL);
 442 	}
 443 
 444 	g_object_unref (destination);
 445 }
 446 
 447 static void
 448 contact_list_editor_selection_changed_cb (GtkTreeSelection *selection,
 449                                           gpointer user_data)
 450 {
 451 	EContactListEditor *editor = user_data;
 452 	GtkTreeModel *model;
 453 	GtkTreeIter iter;
 454 	GtkTreePath *first_item;
 455 	GList *selected;
 456 
 457 	model = gtk_tree_view_get_model (GTK_TREE_VIEW (WIDGET (TREE_VIEW)));
 458 
 459 	/* Is selected anything at all? */
 460 	if (gtk_tree_selection_count_selected_rows (selection) == 0) {
 461 		gtk_widget_set_sensitive (WIDGET (TOP_BUTTON), FALSE);
 462 		gtk_widget_set_sensitive (WIDGET (UP_BUTTON), FALSE);
 463 		gtk_widget_set_sensitive (WIDGET (DOWN_BUTTON), FALSE);
 464 		gtk_widget_set_sensitive (WIDGET (BOTTOM_BUTTON), FALSE);
 465 		gtk_widget_set_sensitive (WIDGET (REMOVE_BUTTON), FALSE);
 466 		return;
 467 	}
 468 
 469 	gtk_widget_set_sensitive (WIDGET (REMOVE_BUTTON), TRUE);
 470 
 471 	/* Item before selected item exists => enable Top/Up buttons */
 472 	selected = gtk_tree_selection_get_selected_rows (selection, &model);
 473 
 474 	/* Don't update path in the list! */
 475 	first_item = gtk_tree_path_copy (selected->data);
 476 	if (gtk_tree_path_prev (first_item)) {
 477 		gtk_widget_set_sensitive (WIDGET (TOP_BUTTON), TRUE);
 478 		gtk_widget_set_sensitive (WIDGET (UP_BUTTON), TRUE);
 479 	} else {
 480 		gtk_widget_set_sensitive (WIDGET (TOP_BUTTON), FALSE);
 481 		gtk_widget_set_sensitive (WIDGET (UP_BUTTON), FALSE);
 482 	}
 483 
 484 	gtk_tree_model_get_iter (model, &iter, g_list_last (selected)->data);
 485 	/* Item below last selected exists => enable Down/Bottom buttons */
 486 	if (gtk_tree_model_iter_next (model, &iter)) {
 487 		gtk_widget_set_sensitive (WIDGET (DOWN_BUTTON), TRUE);
 488 		gtk_widget_set_sensitive (WIDGET (BOTTOM_BUTTON), TRUE);
 489 	} else {
 490 		gtk_widget_set_sensitive (WIDGET (DOWN_BUTTON), FALSE);
 491 		gtk_widget_set_sensitive (WIDGET (BOTTOM_BUTTON), FALSE);
 492 	}
 493 
 494 	g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
 495 	g_list_free (selected);
 496 	gtk_tree_path_free (first_item);
 497 }
 498 
 499 static void
 500 contact_list_editor_add_from_email_entry (EContactListEditor *editor,
 501 					  ENameSelectorEntry *entry)
 502 {
 503 	EDestinationStore *store;
 504 	GList *dests, *diter;
 505 	gboolean added = FALSE;
 506 
 507 	g_return_if_fail (E_IS_CONTACT_LIST_EDITOR (editor));
 508 	g_return_if_fail (E_IS_NAME_SELECTOR_ENTRY (entry));
 509 
 510 	store = e_name_selector_entry_peek_destination_store (entry);
 511 	dests = e_destination_store_list_destinations (store);
 512 
 513 	for (diter = dests; diter; diter = g_list_next (diter)) {
 514 		EDestination *dest = diter->data;
 515 
 516 		if (dest && e_destination_get_address (dest)) {
 517 			editor->priv->changed = contact_list_editor_add_destination (WIDGET (DIALOG), dest)
 518 						|| editor->priv->changed;
 519 			added = TRUE;
 520 		}
 521 	}
 522 
 523 	g_list_free (dests);
 524 
 525 	if (!added)
 526 		contact_list_editor_add_email (editor, gtk_entry_get_text (GTK_ENTRY (entry)));
 527 }
 528 
 529 /*********************** Autoconnected Signal Handlers ***********************/
 530 
 531 void
 532 contact_list_editor_add_button_clicked_cb (GtkWidget *widget);
 533 
 534 void
 535 contact_list_editor_add_button_clicked_cb (GtkWidget *widget)
 536 {
 537 	EContactListEditor *editor;
 538 
 539 	editor = contact_list_editor_extract (widget);
 540 
 541 	contact_list_editor_add_from_email_entry (
 542 		editor,
 543 		E_NAME_SELECTOR_ENTRY (WIDGET (EMAIL_ENTRY)));
 544 	gtk_entry_set_text (GTK_ENTRY (WIDGET (EMAIL_ENTRY)), "");
 545 }
 546 
 547 void
 548 contact_list_editor_cancel_button_clicked_cb (GtkWidget *widget);
 549 
 550 void
 551 contact_list_editor_cancel_button_clicked_cb (GtkWidget *widget)
 552 {
 553 	EContactListEditor *editor;
 554 	GtkWindow *window;
 555 
 556 	editor = contact_list_editor_extract (widget);
 557 	window = GTK_WINDOW (WIDGET (DIALOG));
 558 
 559 	eab_editor_prompt_to_save_changes (EAB_EDITOR (editor), window);
 560 }
 561 
 562 void
 563 contact_list_editor_check_button_toggled_cb (GtkWidget *widget);
 564 
 565 void
 566 contact_list_editor_check_button_toggled_cb (GtkWidget *widget)
 567 {
 568 	EContactListEditor *editor;
 569 
 570 	editor = contact_list_editor_extract (widget);
 571 
 572 	editor->priv->changed = TRUE;
 573 	contact_list_editor_update (editor);
 574 }
 575 
 576 gboolean
 577 contact_list_editor_delete_event_cb (GtkWidget *widget,
 578                                      GdkEvent *event);
 579 
 580 gboolean
 581 contact_list_editor_delete_event_cb (GtkWidget *widget,
 582                                      GdkEvent *event)
 583 {
 584 	EContactListEditor *editor;
 585 	GtkWindow *window;
 586 
 587 	editor = contact_list_editor_extract (widget);
 588 	window = GTK_WINDOW (WIDGET (DIALOG));
 589 
 590 	/* If we're in an async call, don't allow the dialog to close. */
 591 	if (!editor->priv->in_async_call)
 592 		eab_editor_prompt_to_save_changes (
 593 			EAB_EDITOR (editor), window);
 594 
 595 	return TRUE;
 596 }
 597 
 598 void
 599 contact_list_editor_drag_data_received_cb (GtkWidget *widget,
 600                                            GdkDragContext *context,
 601                                            gint x,
 602                                            gint y,
 603                                            GtkSelectionData *selection_data,
 604                                            guint info,
 605                                            guint time);
 606 
 607 void
 608 contact_list_editor_drag_data_received_cb (GtkWidget *widget,
 609                                            GdkDragContext *context,
 610                                            gint x,
 611                                            gint y,
 612                                            GtkSelectionData *selection_data,
 613                                            guint info,
 614                                            guint time)
 615 {
 616 	CamelInternetAddress *address;
 617 	EContactListEditor *editor;
 618 	gboolean changed = FALSE;
 619 	gboolean handled = FALSE;
 620 	const guchar *data;
 621 	GSList *list, *iter;
 622 	GdkAtom target;
 623 	gint n_addresses = 0;
 624 	gchar *text;
 625 
 626 	editor = contact_list_editor_extract (widget);
 627 
 628 	target = gtk_selection_data_get_target (selection_data);
 629 
 630 	/* Sanity check the selection target. */
 631 
 632 	if (gtk_targets_include_text (&target, 1))
 633 		goto handle_text;
 634 
 635 	if (!e_targets_include_directory (&target, 1))
 636 		goto exit;
 637 
 638 	data = gtk_selection_data_get_data (selection_data);
 639 	list = eab_contact_list_from_string ((gchar *) data);
 640 
 641 	if (list != NULL)
 642 		handled = TRUE;
 643 
 644 	for (iter = list; iter != NULL; iter = iter->next) {
 645 		EContact *contact = iter->data;
 646 		EDestination *dest;
 647 
 648 		dest = e_destination_new ();
 649 		e_destination_set_contact (dest, contact, 0);
 650 
 651 		changed = contact_list_editor_add_destination (widget, dest) || changed;
 652 
 653 		g_object_unref (dest);
 654 	}
 655 
 656 	e_client_util_free_object_slist (list);
 657 
 658 	contact_list_editor_scroll_to_end (editor);
 659 
 660 	if (changed) {
 661 		editor->priv->changed = TRUE;
 662 		contact_list_editor_update (editor);
 663 	}
 664 
 665 	goto exit;
 666 
 667 handle_text:
 668 
 669 	address = camel_internet_address_new ();
 670 	text = (gchar *) gtk_selection_data_get_text (selection_data);
 671 
 672 	/* See if Camel can parse a valid email address from the text. */
 673 	if (text != NULL && *text != '\0') {
 674 		camel_url_decode (text);
 675 		if (g_ascii_strncasecmp (text, "mailto:", 7) == 0)
 676 			n_addresses = camel_address_decode (
 677 				CAMEL_ADDRESS (address), text + 7);
 678 		else
 679 			n_addresses = camel_address_decode (
 680 				CAMEL_ADDRESS (address), text);
 681 	}
 682 
 683 	if (n_addresses == 1) {
 684 		g_free (text);
 685 
 686 		text = camel_address_format (CAMEL_ADDRESS (address));
 687 		contact_list_editor_add_email (editor, text);
 688 
 689 		contact_list_editor_scroll_to_end (editor);
 690 		editor->priv->changed = TRUE;
 691 
 692 		contact_list_editor_update (editor);
 693 		handled = TRUE;
 694 	}
 695 
 696 	g_free (text);
 697 
 698 exit:
 699 	gtk_drag_finish (context, handled, FALSE, time);
 700 }
 701 
 702 void
 703 contact_list_editor_email_entry_activate_cb (GtkWidget *widget);
 704 
 705 void
 706 contact_list_editor_email_entry_activate_cb (GtkWidget *widget)
 707 {
 708 	EContactListEditor *editor;
 709 	GtkEntry *entry;
 710 
 711 	editor = contact_list_editor_extract (widget);
 712 	entry = GTK_ENTRY (WIDGET (EMAIL_ENTRY));
 713 
 714 	contact_list_editor_add_from_email_entry (
 715 		editor,
 716 		E_NAME_SELECTOR_ENTRY (entry));
 717 	gtk_entry_set_text (entry, "");
 718 }
 719 
 720 void
 721 contact_list_editor_email_entry_changed_cb (GtkWidget *widget);
 722 
 723 void
 724 contact_list_editor_email_entry_changed_cb (GtkWidget *widget)
 725 {
 726 	EContactListEditor *editor;
 727 	const gchar *text;
 728 	gboolean sensitive;
 729 
 730 	editor = contact_list_editor_extract (widget);
 731 	text = gtk_entry_get_text (GTK_ENTRY (widget));
 732 
 733 	sensitive = (text != NULL && *text != '\0');
 734 	gtk_widget_set_sensitive (WIDGET (ADD_BUTTON), sensitive);
 735 }
 736 
 737 gboolean
 738 contact_list_editor_email_entry_key_press_event_cb (GtkWidget *widget,
 739                                                     GdkEventKey *event);
 740 
 741 gboolean
 742 contact_list_editor_email_entry_key_press_event_cb (GtkWidget *widget,
 743                                                     GdkEventKey *event)
 744 {
 745 	EContactListEditor *editor;
 746 	gboolean can_comma = FALSE;
 747 
 748 	editor = contact_list_editor_extract (widget);
 749 
 750 	if (event->keyval == GDK_KEY_comma) {
 751 		GtkEntry *entry;
 752 		gint cpos = -1;
 753 
 754 		entry = GTK_ENTRY (WIDGET (EMAIL_ENTRY));
 755 		g_object_get (entry, "cursor-position", &cpos, NULL);
 756 
 757 		/* not the first letter */
 758 		if (cpos > 0) {
 759 			const gchar *text;
 760 			gint quotes = 0, i;
 761 
 762 			text = gtk_entry_get_text (entry);
 763 
 764 			for (i = 0; text && text[i] && i < cpos; i++) {
 765 				if (text[i] == '\"')
 766 					quotes++;
 767 			}
 768 
 769 			/* even count of quotes */
 770 			can_comma = (quotes & 1) == 0;
 771 		}
 772 	}
 773 
 774 	if (can_comma || event->keyval == GDK_KEY_Return) {
 775 		g_signal_emit_by_name (WIDGET (EMAIL_ENTRY), "activate", 0);
 776 
 777 		return TRUE;
 778 	}
 779 
 780 	return FALSE;
 781 }
 782 
 783 void
 784 contact_list_editor_list_name_entry_changed_cb (GtkWidget *widget);
 785 
 786 void
 787 contact_list_editor_list_name_entry_changed_cb (GtkWidget *widget)
 788 {
 789 	EContactListEditor *editor;
 790 	const gchar *title;
 791 
 792 	editor = contact_list_editor_extract (widget);
 793 
 794 	title = gtk_entry_get_text (GTK_ENTRY (widget));
 795 
 796 	if (title == NULL || *title == '\0')
 797 		title = _("Contact List Editor");
 798 
 799 	gtk_window_set_title (GTK_WINDOW (WIDGET (DIALOG)), title);
 800 
 801 	editor->priv->changed = TRUE;
 802 	contact_list_editor_update (editor);
 803 }
 804 
 805 void
 806 contact_list_editor_ok_button_clicked_cb (GtkWidget *widget);
 807 
 808 void
 809 contact_list_editor_ok_button_clicked_cb (GtkWidget *widget)
 810 {
 811 	EContactListEditor *editor;
 812 	gboolean save_contact;
 813 
 814 	editor = contact_list_editor_extract (widget);
 815 
 816 	save_contact =
 817 		editor->priv->editable &&
 818 		editor->priv->allows_contact_lists;
 819 
 820 	if (save_contact)
 821 		eab_editor_save_contact (EAB_EDITOR (editor), TRUE);
 822 	else
 823 		eab_editor_close (EAB_EDITOR (editor));
 824 }
 825 
 826 void
 827 contact_list_editor_remove_button_clicked_cb (GtkWidget *widget);
 828 
 829 void
 830 contact_list_editor_remove_button_clicked_cb (GtkWidget *widget)
 831 {
 832 	EContactListEditor *editor;
 833 	GtkTreeSelection *selection;
 834 	GtkTreeRowReference *new_selection = NULL;
 835 	GtkTreeModel *model;
 836 	GtkTreeView *view;
 837 	GtkTreePath *path;
 838 	GList *list, *liter;
 839 
 840 	editor = contact_list_editor_extract (widget);
 841 
 842 	view = GTK_TREE_VIEW (WIDGET (TREE_VIEW));
 843 	selection = gtk_tree_view_get_selection (view);
 844 	list = gtk_tree_selection_get_selected_rows (selection, &model);
 845 
 846 	/* Convert the GtkTreePaths to GtkTreeRowReferences. */
 847 	for (liter = list; liter != NULL; liter = liter->next) {
 848 		path = liter->data;
 849 
 850 		liter->data = gtk_tree_row_reference_new (model, path);
 851 
 852 		/* Store reference to next item below current selection */
 853 		if (!liter->next) {
 854 			gtk_tree_path_next (path);
 855 			new_selection = gtk_tree_row_reference_new (model, path);
 856 		}
 857 
 858 		gtk_tree_path_free (path);
 859 	}
 860 
 861 	/* Delete each row in the list. */
 862 	for (liter = list; liter != NULL; liter = liter->next) {
 863 		GtkTreeRowReference *reference = liter->data;
 864 		GtkTreeIter iter;
 865 		gboolean valid;
 866 
 867 		path = gtk_tree_row_reference_get_path (reference);
 868 		valid = gtk_tree_model_get_iter (model, &iter, path);
 869 		gtk_tree_path_free (path);
 870 		g_assert (valid);
 871 
 872 		e_contact_list_model_remove_row (E_CONTACT_LIST_MODEL (model), &iter);
 873 		gtk_tree_row_reference_free (reference);
 874 	}
 875 
 876 	/* new_selection != NULL when there is at least one item below the
 877 	 * removed selection */
 878 	if (new_selection) {
 879 		path = gtk_tree_row_reference_get_path (new_selection);
 880 		gtk_tree_selection_select_path (selection, path);
 881 		gtk_tree_path_free (path);
 882 		gtk_tree_row_reference_free (new_selection);
 883 	} else {
 884 		/* If selection was including the last item in the list, then
 885 		 * find and select the new last item */
 886 		GtkTreeIter iter, iter2;
 887 
 888 		/* When FALSE is returned, there are no items in the list to be selected */
 889 		if (gtk_tree_model_get_iter_first (model, &iter)) {
 890 			iter2 = iter;
 891 
 892 			while (gtk_tree_model_iter_next (model, &iter))
 893 				iter2 = iter;
 894 
 895 			gtk_tree_selection_select_iter (selection, &iter2);
 896 		}
 897 	}
 898 
 899 	g_list_free (list);
 900 
 901 	editor->priv->changed = TRUE;
 902 	contact_list_editor_update (editor);
 903 }
 904 
 905 void
 906 contact_list_editor_select_button_clicked_cb (GtkWidget *widget);
 907 
 908 void
 909 contact_list_editor_select_button_clicked_cb (GtkWidget *widget)
 910 {
 911 	EContactListEditor *editor;
 912 	ENameSelectorDialog *dialog;
 913 	EDestinationStore *store;
 914 	GList *list, *iter;
 915 	GtkWindow *window;
 916 
 917 	editor = contact_list_editor_extract (widget);
 918 
 919 	dialog = e_name_selector_peek_dialog (editor->priv->name_selector);
 920 	gtk_window_set_title (GTK_WINDOW (dialog), _("Contact List Members"));
 921 
 922 	/* We need to empty out the destination store, since we copy its
 923 	 * contents every time.  This sucks, we should really be wired
 924 	 * directly to the EDestinationStore that the name selector uses
 925 	 * in true MVC fashion. */
 926 
 927 	e_name_selector_model_peek_section (
 928 		e_name_selector_peek_model (editor->priv->name_selector),
 929 		"Members", NULL, &store);
 930 
 931 	list = e_destination_store_list_destinations (store);
 932 
 933 	for (iter = list; iter != NULL; iter = iter->next)
 934 		e_destination_store_remove_destination (store, iter->data);
 935 
 936 	g_list_free (list);
 937 
 938 	window = eab_editor_get_window (EAB_EDITOR (editor));
 939 	e_name_selector_show_dialog (
 940 		editor->priv->name_selector, GTK_WIDGET (window));
 941 	gtk_dialog_run (GTK_DIALOG (dialog));
 942 	gtk_widget_hide (GTK_WIDGET (dialog));
 943 
 944 	list = e_destination_store_list_destinations (store);
 945 
 946 	for (iter = list; iter != NULL; iter = iter->next) {
 947 		EDestination *destination = iter->data;
 948 
 949 		contact_list_editor_add_destination (widget, destination);
 950 		e_destination_store_remove_destination (store, destination);
 951 	}
 952 
 953 	g_list_free (list);
 954 
 955 	gtk_entry_set_text (GTK_ENTRY (WIDGET (EMAIL_ENTRY)), "");
 956 
 957 	editor->priv->changed = TRUE;
 958 	contact_list_editor_update (editor);
 959 }
 960 
 961 void
 962 contact_list_editor_source_menu_changed_cb (GtkWidget *widget);
 963 
 964 void
 965 contact_list_editor_source_menu_changed_cb (GtkWidget *widget)
 966 {
 967 	ESourceComboBox *combo_box;
 968 	EContactListEditor *editor;
 969 	ESource *active_source;
 970 	ESource *client_source;
 971 	EClient *client;
 972 
 973 	editor = contact_list_editor_extract (widget);
 974 
 975 	combo_box = E_SOURCE_COMBO_BOX (widget);
 976 	active_source = e_source_combo_box_ref_active (combo_box);
 977 	g_return_if_fail (active_source != NULL);
 978 
 979 	client = E_CLIENT (editor->priv->book_client);
 980 	client_source = e_client_get_source (client);
 981 
 982 	if (!e_source_equal (client_source, active_source))
 983 		e_client_utils_open_new (
 984 			active_source, E_CLIENT_SOURCE_TYPE_CONTACTS,
 985 			FALSE, NULL, contact_list_editor_book_loaded_cb,
 986 			g_object_ref (editor));
 987 
 988 	g_object_unref (active_source);
 989 }
 990 
 991 gboolean
 992 contact_list_editor_tree_view_key_press_event_cb (GtkWidget *widget,
 993                                                   GdkEventKey *event);
 994 gboolean
 995 contact_list_editor_tree_view_key_press_event_cb (GtkWidget *widget,
 996                                                   GdkEventKey *event)
 997 {
 998 	EContactListEditor *editor;
 999 
1000 	editor = contact_list_editor_extract (widget);
1001 
1002 	if (event->keyval == GDK_KEY_Delete) {
1003 		g_signal_emit_by_name (WIDGET (REMOVE_BUTTON), "clicked");
1004 		return TRUE;
1005 	}
1006 
1007 	return FALSE;
1008 }
1009 
1010 void
1011 contact_list_editor_top_button_clicked_cb (GtkButton *button);
1012 
1013 void
1014 contact_list_editor_top_button_clicked_cb (GtkButton *button)
1015 {
1016 	EContactListEditor *editor;
1017 	GtkTreeView *tree_view;
1018 	GtkTreeModel *model;
1019 	GtkTreeSelection *selection;
1020 	GtkTreeIter iter;
1021 	GtkTreePath *path;
1022 	GList *references = NULL;
1023 	GList *l, *selected;
1024 
1025 	editor = contact_list_editor_extract (GTK_WIDGET (button));
1026 
1027 	tree_view = GTK_TREE_VIEW (WIDGET (TREE_VIEW));
1028 	model = gtk_tree_view_get_model (tree_view);
1029 	selection = gtk_tree_view_get_selection (tree_view);
1030 
1031 	selected = gtk_tree_selection_get_selected_rows (selection, &model);
1032 
1033 	for (l = selected; l; l = l->next)
1034 		references = g_list_prepend (
1035 			references,
1036 			gtk_tree_row_reference_new (model, l->data));
1037 
1038 	for (l = references; l; l = l->next) {
1039 		path = gtk_tree_row_reference_get_path (l->data);
1040 		gtk_tree_model_get_iter (model, &iter, path);
1041 		gtk_tree_store_move_after (
1042 			GTK_TREE_STORE (model), &iter, NULL);
1043 		gtk_tree_path_free (path);
1044 	}
1045 
1046 	g_list_foreach (references, (GFunc) gtk_tree_row_reference_free, NULL);
1047 	g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1048 	g_list_free (references);
1049 	g_list_free (selected);
1050 
1051 	contact_list_editor_selection_changed_cb (selection, editor);
1052 }
1053 
1054 void
1055 contact_list_editor_up_button_clicked_cb (GtkButton *button);
1056 
1057 void
1058 contact_list_editor_up_button_clicked_cb (GtkButton *button)
1059 {
1060 	EContactListEditor *editor;
1061 	GtkTreeView *tree_view;
1062 	GtkTreeModel *model;
1063 	GtkTreeSelection *selection;
1064 	GtkTreeIter iter, iter2;
1065 	GtkTreePath *path;
1066 	GList *selected;
1067 
1068 	editor = contact_list_editor_extract (GTK_WIDGET (button));
1069 
1070 	tree_view = GTK_TREE_VIEW (WIDGET (TREE_VIEW));
1071 	model = gtk_tree_view_get_model (tree_view);
1072 	selection = gtk_tree_view_get_selection (tree_view);
1073 
1074 	selected = gtk_tree_selection_get_selected_rows (selection, &model);
1075 
1076 	/* Get iter of item above the first selected item */
1077 	path = gtk_tree_path_copy (selected->data);
1078 	gtk_tree_path_prev (path);
1079 	gtk_tree_model_get_iter (model, &iter, path);
1080 	gtk_tree_path_free (path);
1081 
1082 	/* Get iter of the last selected item */
1083 	gtk_tree_model_get_iter (model, &iter2, g_list_last (selected)->data);
1084 
1085 	gtk_tree_store_move_after (GTK_TREE_STORE (model), &iter, &iter2);
1086 
1087 	g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1088 	g_list_free (selected);
1089 
1090 	contact_list_editor_selection_changed_cb (selection, editor);
1091 }
1092 
1093 void
1094 contact_list_editor_down_button_clicked_cb (GtkButton *button);
1095 
1096 void
1097 contact_list_editor_down_button_clicked_cb (GtkButton *button)
1098 {
1099 	EContactListEditor *editor;
1100 	GtkTreeView *tree_view;
1101 	GtkTreeModel *model;
1102 	GtkTreeSelection *selection;
1103 	GtkTreeIter iter, iter2;
1104 	GList *selected;
1105 
1106 	editor = contact_list_editor_extract (GTK_WIDGET (button));
1107 
1108 	tree_view = GTK_TREE_VIEW (WIDGET (TREE_VIEW));
1109 	model = gtk_tree_view_get_model (tree_view);
1110 	selection = gtk_tree_view_get_selection (tree_view);
1111 
1112 	selected = gtk_tree_selection_get_selected_rows (selection, &model);
1113 
1114 	/* Iter of the first selected item */
1115 	gtk_tree_model_get_iter (model, &iter, selected->data);
1116 
1117 	/* Iter of item below the last selected item */
1118 	gtk_tree_model_get_iter (model, &iter2, g_list_last (selected)->data);
1119 	gtk_tree_model_iter_next (model, &iter2);
1120 
1121 	gtk_tree_store_move_before (GTK_TREE_STORE (model), &iter2, &iter);
1122 
1123 	g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1124 	g_list_free (selected);
1125 
1126 	contact_list_editor_selection_changed_cb (selection, editor);
1127 }
1128 
1129 void
1130 contact_list_editor_bottom_button_clicked_cb (GtkButton *button);
1131 
1132 void
1133 contact_list_editor_bottom_button_clicked_cb (GtkButton *button)
1134 {
1135 	EContactListEditor *editor;
1136 	GtkTreeView *tree_view;
1137 	GtkTreeModel *model;
1138 	GtkTreeSelection *selection;
1139 	GtkTreeIter iter;
1140 	GtkTreePath *path;
1141 	GList *references = NULL;
1142 
1143 	GList *l, *selected;
1144 
1145 	editor = contact_list_editor_extract (GTK_WIDGET (button));
1146 
1147 	tree_view = GTK_TREE_VIEW (WIDGET (TREE_VIEW));
1148 	model = gtk_tree_view_get_model (tree_view);
1149 	selection = gtk_tree_view_get_selection (tree_view);
1150 
1151 	selected = gtk_tree_selection_get_selected_rows (selection, &model);
1152 	for (l = selected; l; l = l->next)
1153 		references = g_list_prepend (
1154 			references,
1155 			gtk_tree_row_reference_new (model, l->data));
1156 	references = g_list_reverse (references);
1157 
1158 	for (l = references; l; l = l->next) {
1159 		path = gtk_tree_row_reference_get_path (l->data);
1160 		gtk_tree_model_get_iter (model, &iter, path);
1161 		gtk_tree_store_move_before (
1162 			GTK_TREE_STORE (model), &iter, NULL);
1163 		gtk_tree_path_free (path);
1164 	}
1165 
1166 	g_list_foreach (references, (GFunc) gtk_tree_row_reference_free, NULL);
1167 	g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1168 	g_list_free (references);
1169 	g_list_free (selected);
1170 
1171 	contact_list_editor_selection_changed_cb (selection, editor);
1172 }
1173 
1174 /******************** GtkBuilder Custom Widgets Functions ********************/
1175 
1176 static gpointer
1177 contact_editor_fudge_new (EBookClient *book_client,
1178                           EContact *contact,
1179                           gboolean is_new,
1180                           gboolean editable)
1181 {
1182 	EShell *shell = e_shell_get_default ();
1183 
1184 	/* XXX Putting this function signature in libedataserverui
1185 	 *     was a terrible idea.  Now we're stuck with it. */
1186 
1187 	return e_contact_editor_new (
1188 		shell, book_client, contact, is_new, editable);
1189 }
1190 
1191 static gpointer
1192 contact_list_editor_fudge_new (EBookClient *book_client,
1193                                EContact *contact,
1194                                gboolean is_new,
1195                                gboolean editable)
1196 {
1197 	EShell *shell = e_shell_get_default ();
1198 
1199 	/* XXX Putting this function signature in libedataserverui
1200 	 *     was a terrible idea.  Now we're stuck with it. */
1201 
1202 	return e_contact_list_editor_new (
1203 		shell, book_client, contact, is_new, editable);
1204 }
1205 
1206 static void
1207 setup_custom_widgets (EContactListEditor *editor)
1208 {
1209 	EShell *shell;
1210 	ESourceRegistry *registry;
1211 	GtkWidget *combo_box;
1212 	ENameSelectorEntry *name_selector_entry;
1213 	GtkWidget *old, *parent;
1214 	EContactListEditorPrivate *priv;
1215 	guint ba = 0, la = 0, ra = 0, ta = 0, xo = 0, xp = 0, yo = 0, yp = 0;
1216 
1217 	g_return_if_fail (editor != NULL);
1218 
1219 	priv = E_CONTACT_LIST_EDITOR_GET_PRIVATE (editor);
1220 
1221 	shell = eab_editor_get_shell (EAB_EDITOR (editor));
1222 	registry = e_shell_get_registry (shell);
1223 
1224 	combo_box = WIDGET (SOURCE_MENU);
1225 
1226 	e_source_combo_box_set_registry (
1227 		E_SOURCE_COMBO_BOX (combo_box), registry);
1228 
1229 	g_signal_connect (
1230 		combo_box, "changed", G_CALLBACK (
1231 		contact_list_editor_source_menu_changed_cb), NULL);
1232 
1233 	old = CONTACT_LIST_EDITOR_WIDGET (editor, "email-entry");
1234 	g_return_if_fail (old != NULL);
1235 
1236 	name_selector_entry = e_name_selector_peek_section_entry (
1237 		priv->name_selector, "Members");
1238 
1239 	gtk_widget_set_name (
1240 		GTK_WIDGET (name_selector_entry),
1241 		gtk_widget_get_name (old));
1242 	parent = gtk_widget_get_parent (old);
1243 
1244 	gtk_container_child_get (
1245 		GTK_CONTAINER (parent), old,
1246 		"bottom-attach", &ba,
1247 		"left-attach", &la,
1248 		"right-attach", &ra,
1249 		"top-attach", &ta,
1250 		"x-options", &xo,
1251 		"x-padding", &xp,
1252 		"y-options", &yo,
1253 		"y-padding", &yp,
1254 		NULL);
1255 
1256 	/* only hide it... */
1257 	gtk_widget_hide (old);
1258 
1259 	/* ... and place the new name selector to the
1260 	 * exact place as is the old one in UI file */
1261 	gtk_widget_show (GTK_WIDGET (name_selector_entry));
1262 	gtk_table_attach (
1263 		GTK_TABLE (parent), GTK_WIDGET (name_selector_entry),
1264 		la, ra, ta, ba, xo, yo, xp, yp);
1265 	priv->email_entry = name_selector_entry;
1266 
1267 	e_name_selector_entry_set_contact_editor_func (
1268 		name_selector_entry, contact_editor_fudge_new);
1269 	e_name_selector_entry_set_contact_list_editor_func (
1270 		name_selector_entry, contact_list_editor_fudge_new);
1271 
1272 	g_signal_connect (
1273 		name_selector_entry, "activate", G_CALLBACK (
1274 		contact_list_editor_email_entry_activate_cb), NULL);
1275 	g_signal_connect (
1276 		name_selector_entry, "changed", G_CALLBACK (
1277 		contact_list_editor_email_entry_changed_cb), NULL);
1278 	g_signal_connect (
1279 		name_selector_entry, "key-press-event", G_CALLBACK (
1280 		contact_list_editor_email_entry_key_press_event_cb), NULL);
1281 }
1282 
1283 /***************************** GObject Callbacks *****************************/
1284 
1285 static void
1286 contact_list_editor_set_property (GObject *object,
1287                                   guint property_id,
1288                                   const GValue *value,
1289                                   GParamSpec *pspec)
1290 {
1291 	switch (property_id) {
1292 		case PROP_CLIENT:
1293 			e_contact_list_editor_set_client (
1294 				E_CONTACT_LIST_EDITOR (object),
1295 				g_value_get_object (value));
1296 			return;
1297 
1298 		case PROP_CONTACT:
1299 			e_contact_list_editor_set_contact (
1300 				E_CONTACT_LIST_EDITOR (object),
1301 				g_value_get_object (value));
1302 			return;
1303 
1304 		case PROP_IS_NEW_LIST:
1305 			e_contact_list_editor_set_is_new_list (
1306 				E_CONTACT_LIST_EDITOR (object),
1307 				g_value_get_boolean (value));
1308 			return;
1309 
1310 		case PROP_EDITABLE:
1311 			e_contact_list_editor_set_editable (
1312 				E_CONTACT_LIST_EDITOR (object),
1313 				g_value_get_boolean (value));
1314 			return;
1315 	}
1316 
1317 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1318 }
1319 
1320 static void
1321 contact_list_editor_get_property (GObject *object,
1322                                   guint property_id,
1323                                   GValue *value,
1324                                   GParamSpec *pspec)
1325 {
1326 	switch (property_id) {
1327 		case PROP_CLIENT:
1328 			g_value_set_object (
1329 				value,
1330 				e_contact_list_editor_get_client (
1331 				E_CONTACT_LIST_EDITOR (object)));
1332 			return;
1333 
1334 		case PROP_CONTACT:
1335 			g_value_set_object (
1336 				value,
1337 				e_contact_list_editor_get_contact (
1338 				E_CONTACT_LIST_EDITOR (object)));
1339 			return;
1340 
1341 		case PROP_IS_NEW_LIST:
1342 			g_value_set_boolean (
1343 				value,
1344 				e_contact_list_editor_get_is_new_list (
1345 				E_CONTACT_LIST_EDITOR (object)));
1346 			return;
1347 
1348 		case PROP_EDITABLE:
1349 			g_value_set_boolean (
1350 				value,
1351 				e_contact_list_editor_get_editable (
1352 				E_CONTACT_LIST_EDITOR (object)));
1353 			return;
1354 	}
1355 
1356 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1357 }
1358 
1359 static void
1360 contact_list_editor_dispose (GObject *object)
1361 {
1362 	EContactListEditor *editor = E_CONTACT_LIST_EDITOR (object);
1363 	EContactListEditorPrivate *priv = editor->priv;
1364 
1365 	if (priv->name_selector) {
1366 		e_name_selector_cancel_loading (priv->name_selector);
1367 		g_object_unref (priv->name_selector);
1368 		priv->name_selector = NULL;
1369 	}
1370 
1371 	if (priv->contact) {
1372 		g_object_unref (priv->contact);
1373 		priv->contact = NULL;
1374 	}
1375 
1376 	if (priv->builder) {
1377 		g_object_unref (priv->builder);
1378 		priv->builder = NULL;
1379 	}
1380 
1381 	/* Chain up to parent's dispose() method. */
1382 	G_OBJECT_CLASS (e_contact_list_editor_parent_class)->dispose (object);
1383 }
1384 
1385 static void
1386 contact_list_editor_constructed (GObject *object)
1387 {
1388 	EContactListEditor *editor;
1389 	GtkTreeViewColumn *column;
1390 	GtkCellRenderer *renderer;
1391 	GtkTreeView *view;
1392 	GtkTreeSelection *selection;
1393 	ESourceRegistry *registry;
1394 	EShell *shell;
1395 
1396 	editor = E_CONTACT_LIST_EDITOR (object);
1397 
1398 	/* Chain up to parent's constructed() method. */
1399 	G_OBJECT_CLASS (e_contact_list_editor_parent_class)->
1400 		constructed (object);
1401 
1402 	shell = eab_editor_get_shell (EAB_EDITOR (editor));
1403 	registry = e_shell_get_registry (shell);
1404 
1405 	editor->priv->editable = TRUE;
1406 	editor->priv->allows_contact_lists = TRUE;
1407 
1408 	editor->priv->builder = gtk_builder_new ();
1409 	e_load_ui_builder_definition (
1410 		editor->priv->builder, "contact-list-editor.ui");
1411 	gtk_builder_connect_signals (editor->priv->builder, NULL);
1412 
1413 	/* Embed a pointer to the EContactListEditor in the top-level
1414 	 * widget.  Signal handlers can then access the pointer from any
1415 	 * child widget by calling contact_list_editor_extract(widget). */
1416 	g_object_set_data (G_OBJECT (WIDGET (DIALOG)), TOPLEVEL_KEY, editor);
1417 
1418 	view = GTK_TREE_VIEW (WIDGET (TREE_VIEW));
1419 	editor->priv->model = e_contact_list_model_new ();
1420 	gtk_tree_view_set_model (view, editor->priv->model);
1421 
1422 	selection = gtk_tree_view_get_selection (view);
1423 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
1424 	g_signal_connect (
1425 		selection, "changed",
1426 		G_CALLBACK (contact_list_editor_selection_changed_cb), editor);
1427 
1428 	gtk_tree_view_enable_model_drag_dest (view, NULL, 0, GDK_ACTION_LINK);
1429 	e_drag_dest_add_directory_targets (WIDGET (TREE_VIEW));
1430 	gtk_drag_dest_add_text_targets (WIDGET (TREE_VIEW));
1431 
1432 	column = gtk_tree_view_column_new ();
1433 	renderer = gtk_cell_renderer_text_new ();
1434 	g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1435 	gtk_tree_view_column_pack_start (column, renderer, TRUE);
1436 	gtk_tree_view_append_column (view, column);
1437 
1438 	gtk_tree_view_column_set_cell_data_func (
1439 		column, renderer, (GtkTreeCellDataFunc)
1440 		contact_list_editor_render_destination, NULL, NULL);
1441 
1442 	editor->priv->name_selector = e_name_selector_new (registry);
1443 
1444 	e_name_selector_model_add_section (
1445 		e_name_selector_peek_model (editor->priv->name_selector),
1446 		"Members", _("_Members"), NULL);
1447 
1448 	g_signal_connect (
1449 		editor, "notify::book",
1450 		G_CALLBACK (contact_list_editor_notify_cb), NULL);
1451 	g_signal_connect (
1452 		editor, "notify::editable",
1453 		G_CALLBACK (contact_list_editor_notify_cb), NULL);
1454 
1455 	gtk_widget_show_all (WIDGET (DIALOG));
1456 
1457 	setup_custom_widgets (editor);
1458 
1459 	e_name_selector_load_books (editor->priv->name_selector);
1460 
1461 	contact_list_editor_update (E_CONTACT_LIST_EDITOR (object));
1462 }
1463 
1464 /**************************** EABEditor Callbacks ****************************/
1465 
1466 static void
1467 contact_list_editor_show (EABEditor *editor)
1468 {
1469 	gtk_widget_show (WIDGET (DIALOG));
1470 }
1471 
1472 static void
1473 contact_list_editor_close (EABEditor *editor)
1474 {
1475 	gtk_widget_destroy (WIDGET (DIALOG));
1476 	eab_editor_closed (editor);
1477 }
1478 
1479 static void
1480 contact_list_editor_raise (EABEditor *editor)
1481 {
1482 	GdkWindow *window;
1483 
1484 	window = gtk_widget_get_window (WIDGET (DIALOG));
1485 	gdk_window_raise (window);
1486 }
1487 
1488 static void
1489 contact_list_editor_save_contact (EABEditor *eab_editor,
1490                                   gboolean should_close)
1491 {
1492 	EContactListEditor *editor = E_CONTACT_LIST_EDITOR (eab_editor);
1493 	EContactListEditorPrivate *priv = editor->priv;
1494 	ESourceRegistry *registry;
1495 	EditorCloseStruct *ecs;
1496 	EContact *contact;
1497 	EShell *shell;
1498 
1499 	shell = eab_editor_get_shell (eab_editor);
1500 	registry = e_shell_get_registry (shell);
1501 
1502 	contact = e_contact_list_editor_get_contact (editor);
1503 
1504 	if (priv->book_client == NULL)
1505 		return;
1506 
1507 	ecs = g_new (EditorCloseStruct, 1);
1508 	ecs->editor = g_object_ref (editor);
1509 	ecs->should_close = should_close;
1510 
1511 	gtk_widget_set_sensitive (WIDGET (DIALOG), FALSE);
1512 	priv->in_async_call = TRUE;
1513 
1514 	if (priv->is_new_list)
1515 		eab_merging_book_add_contact (
1516 			registry, priv->book_client, contact,
1517 			contact_list_editor_list_added_cb, ecs);
1518 	else
1519 		eab_merging_book_modify_contact (
1520 			registry, priv->book_client, contact,
1521 			contact_list_editor_list_modified_cb, ecs);
1522 
1523 	priv->changed = FALSE;
1524 }
1525 
1526 static gboolean
1527 contact_list_editor_is_valid (EABEditor *editor)
1528 {
1529 	GtkEditable *editable;
1530 	gboolean valid;
1531 	gchar *chars;
1532 
1533 	editable = GTK_EDITABLE (WIDGET (LIST_NAME_ENTRY));
1534 	chars = gtk_editable_get_chars (editable, 0, -1);
1535 	valid = (chars != NULL && *chars != '\0');
1536 	g_free (chars);
1537 
1538 	return valid;
1539 }
1540 
1541 static gboolean
1542 contact_list_editor_is_changed (EABEditor *editor)
1543 {
1544 	return E_CONTACT_LIST_EDITOR_GET_PRIVATE (editor)->changed;
1545 }
1546 
1547 static GtkWindow *
1548 contact_list_editor_get_window (EABEditor *editor)
1549 {
1550 	return GTK_WINDOW (WIDGET (DIALOG));
1551 }
1552 
1553 static void
1554 contact_list_editor_contact_added (EABEditor *editor,
1555                                    const GError *error,
1556                                    EContact *contact)
1557 {
1558 	if (!error)
1559 		return;
1560 
1561 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
1562 	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1563 		return;
1564 
1565 	eab_error_dialog (NULL, _("Error adding list"), error);
1566 }
1567 
1568 static void
1569 contact_list_editor_contact_modified (EABEditor *editor,
1570                                       const GError *error,
1571                                       EContact *contact)
1572 {
1573 	if (!error)
1574 		return;
1575 
1576 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
1577 	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1578 		return;
1579 
1580 	eab_error_dialog (NULL, _("Error modifying list"), error);
1581 }
1582 
1583 static void
1584 contact_list_editor_contact_deleted (EABEditor *editor,
1585                                      const GError *error,
1586                                      EContact *contact)
1587 {
1588 	if (!error)
1589 		return;
1590 
1591 	if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
1592 	    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1593 		return;
1594 
1595 	eab_error_dialog (NULL, _("Error removing list"), error);
1596 }
1597 
1598 static void
1599 contact_list_editor_closed (EABEditor *editor)
1600 {
1601 	g_object_unref (editor);
1602 }
1603 
1604 /****************************** GType Callbacks ******************************/
1605 
1606 static void
1607 e_contact_list_editor_class_init (EContactListEditorClass *class)
1608 {
1609 	GObjectClass *object_class;
1610 	EABEditorClass *editor_class;
1611 
1612 	g_type_class_add_private (class, sizeof (EContactListEditorPrivate));
1613 
1614 	object_class = G_OBJECT_CLASS (class);
1615 	object_class->set_property = contact_list_editor_set_property;
1616 	object_class->get_property = contact_list_editor_get_property;
1617 	object_class->dispose = contact_list_editor_dispose;
1618 	object_class->constructed = contact_list_editor_constructed;
1619 
1620 	editor_class = EAB_EDITOR_CLASS (class);
1621 	editor_class->show = contact_list_editor_show;
1622 	editor_class->close = contact_list_editor_close;
1623 	editor_class->raise = contact_list_editor_raise;
1624 	editor_class->save_contact = contact_list_editor_save_contact;
1625 	editor_class->is_valid = contact_list_editor_is_valid;
1626 	editor_class->is_changed = contact_list_editor_is_changed;
1627 	editor_class->get_window = contact_list_editor_get_window;
1628 	editor_class->contact_added = contact_list_editor_contact_added;
1629 	editor_class->contact_modified = contact_list_editor_contact_modified;
1630 	editor_class->contact_deleted = contact_list_editor_contact_deleted;
1631 	editor_class->editor_closed = contact_list_editor_closed;
1632 
1633 	g_object_class_install_property (
1634 		object_class,
1635 		PROP_CLIENT,
1636 		g_param_spec_object (
1637 			"client",
1638 			"EBookClient",
1639 			NULL,
1640 			E_TYPE_BOOK_CLIENT,
1641 			G_PARAM_READWRITE));
1642 
1643 	g_object_class_install_property (
1644 		object_class,
1645 		PROP_CONTACT,
1646 		g_param_spec_object (
1647 			"contact",
1648 			"Contact",
1649 			NULL,
1650 			E_TYPE_CONTACT,
1651 			G_PARAM_READWRITE));
1652 
1653 	g_object_class_install_property (
1654 		object_class,
1655 		PROP_IS_NEW_LIST,
1656 		g_param_spec_boolean (
1657 			"is_new_list",
1658 			"Is New List",
1659 			NULL,
1660 			FALSE,
1661 			G_PARAM_READWRITE));
1662 
1663 	g_object_class_install_property (
1664 		object_class,
1665 		PROP_EDITABLE,
1666 		g_param_spec_boolean (
1667 			"editable",
1668 			"Editable",
1669 			NULL,
1670 			FALSE,
1671 			G_PARAM_READWRITE));
1672 }
1673 
1674 static void
1675 e_contact_list_editor_init (EContactListEditor *editor)
1676 {
1677 	editor->priv = E_CONTACT_LIST_EDITOR_GET_PRIVATE (editor);
1678 }
1679 
1680 /***************************** Public Interface ******************************/
1681 
1682 EABEditor *
1683 e_contact_list_editor_new (EShell *shell,
1684                            EBookClient *book_client,
1685                            EContact *list_contact,
1686                            gboolean is_new_list,
1687                            gboolean editable)
1688 {
1689 	EABEditor *editor;
1690 
1691 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
1692 
1693 	editor = g_object_new (
1694 		E_TYPE_CONTACT_LIST_EDITOR,
1695 		"shell", shell, NULL);
1696 
1697 	g_object_set (
1698 		editor,
1699 		"client", book_client,
1700 		"contact", list_contact,
1701 		"is_new_list", is_new_list,
1702 		"editable", editable,
1703 		NULL);
1704 
1705 	return editor;
1706 }
1707 
1708 EBookClient *
1709 e_contact_list_editor_get_client (EContactListEditor *editor)
1710 {
1711 	g_return_val_if_fail (E_IS_CONTACT_LIST_EDITOR (editor), NULL);
1712 
1713 	return editor->priv->book_client;
1714 }
1715 
1716 void
1717 e_contact_list_editor_set_client (EContactListEditor *editor,
1718                                   EBookClient *book_client)
1719 {
1720 	g_return_if_fail (E_IS_CONTACT_LIST_EDITOR (editor));
1721 	g_return_if_fail (E_IS_BOOK_CLIENT (book_client));
1722 
1723 	if (book_client == editor->priv->book_client)
1724 		return;
1725 
1726 	if (editor->priv->book_client != NULL)
1727 		g_object_unref (editor->priv->book_client);
1728 	editor->priv->book_client = g_object_ref (book_client);
1729 
1730 	editor->priv->allows_contact_lists = e_client_check_capability (
1731 		E_CLIENT (editor->priv->book_client), "contact-lists");
1732 
1733 	contact_list_editor_update (editor);
1734 
1735 	g_object_notify (G_OBJECT (editor), "client");
1736 }
1737 
1738 static void
1739 save_contact_list (GtkTreeModel *model,
1740                    GtkTreeIter *iter,
1741                    GSList **attrs,
1742                    gint *parent_id)
1743 {
1744 	EDestination *dest;
1745 	EVCardAttribute *attr;
1746 	gchar *pid_str = g_strdup_printf ("%d", *parent_id);
1747 
1748 	do {
1749 		gtk_tree_model_get (model, iter, 0, &dest, -1);
1750 
1751 		if (gtk_tree_model_iter_has_child (model, iter)) {
1752 			GtkTreeIter new_iter;
1753 			gchar *uid;
1754 
1755 			(*parent_id)++;
1756 			uid = g_strdup_printf ("%d", *parent_id);
1757 
1758 			attr = e_vcard_attribute_new (NULL, EVC_CONTACT_LIST);
1759 			e_vcard_attribute_add_param_with_value (
1760 				attr,
1761 				e_vcard_attribute_param_new (EVC_CL_UID), uid);
1762 			e_vcard_attribute_add_value (
1763 				attr,
1764 				e_destination_get_name (dest));
1765 
1766 			g_free (uid);
1767 
1768 			/* Set new_iter to first child of iter */
1769 			gtk_tree_model_iter_children (model, &new_iter, iter);
1770 
1771 			/* Go recursive */
1772 			save_contact_list (model, &new_iter, attrs, parent_id);
1773 		} else {
1774 			attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
1775 			e_destination_export_to_vcard_attribute (dest, attr);
1776 		}
1777 
1778 		e_vcard_attribute_add_param_with_value (
1779 			attr,
1780 			e_vcard_attribute_param_new (EVC_PARENT_CL), pid_str);
1781 
1782 		*attrs = g_slist_prepend (*attrs, attr);
1783 
1784 		g_object_unref (dest);
1785 
1786 	} while (gtk_tree_model_iter_next (model, iter));
1787 
1788 	g_free (pid_str);
1789 }
1790 
1791 EContact *
1792 e_contact_list_editor_get_contact (EContactListEditor *editor)
1793 {
1794 	GtkTreeModel *model;
1795 	EContact *contact;
1796 	GtkTreeIter iter;
1797 	const gchar *text;
1798 	GSList *attrs = NULL, *a;
1799 	gint parent_id = 0;
1800 
1801 	g_return_val_if_fail (E_IS_CONTACT_LIST_EDITOR (editor), NULL);
1802 
1803 	model = editor->priv->model;
1804 	contact = editor->priv->contact;
1805 
1806 	if (contact == NULL)
1807 		return NULL;
1808 
1809 	text = gtk_entry_get_text (GTK_ENTRY (WIDGET (LIST_NAME_ENTRY)));
1810 	if (text != NULL && *text != '\0') {
1811 		e_contact_set (contact, E_CONTACT_FILE_AS, text);
1812 		e_contact_set (contact, E_CONTACT_FULL_NAME, text);
1813 	}
1814 
1815 	e_contact_set (contact, E_CONTACT_LOGO, NULL);
1816 	e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE));
1817 
1818 	e_contact_set (
1819 		contact, E_CONTACT_LIST_SHOW_ADDRESSES,
1820 		GINT_TO_POINTER (!gtk_toggle_button_get_active (
1821 		GTK_TOGGLE_BUTTON (WIDGET (CHECK_BUTTON)))));
1822 
1823 	e_vcard_remove_attributes (E_VCARD (contact), "", EVC_EMAIL);
1824 	e_vcard_remove_attributes (E_VCARD (contact), "", EVC_CONTACT_LIST);
1825 
1826 	if (gtk_tree_model_get_iter_first (model, &iter))
1827 		save_contact_list (model, &iter, &attrs, &parent_id);
1828 
1829 	/* Put it in reverse order because e_vcard_add_attribute also uses prepend,
1830 	 * but we want to keep order of mails there. Hopefully noone will change
1831 	 * the behaviour of the e_vcard_add_attribute. */
1832 	for (a = attrs; a; a = a->next) {
1833 		e_vcard_add_attribute (E_VCARD (contact), a->data);
1834 	}
1835 
1836 	g_slist_free (attrs);
1837 
1838 	return contact;
1839 }
1840 
1841 void
1842 e_contact_list_editor_set_contact (EContactListEditor *editor,
1843                                    EContact *contact)
1844 {
1845 	EContactListEditorPrivate *priv;
1846 
1847 	g_return_if_fail (E_IS_CONTACT_LIST_EDITOR (editor));
1848 	g_return_if_fail (E_IS_CONTACT (contact));
1849 
1850 	priv = editor->priv;
1851 
1852 	if (priv->contact != NULL)
1853 		g_object_unref (priv->contact);
1854 
1855 	priv->contact = e_contact_duplicate (contact);
1856 
1857 	if (priv->contact != NULL) {
1858 		const gchar *file_as;
1859 		gboolean show_addresses;
1860 		const GList *dests, *dest;
1861 
1862 		/* The root destination */
1863 		EDestination *list_dest = e_destination_new ();
1864 
1865 		file_as = e_contact_get_const (
1866 			priv->contact, E_CONTACT_FILE_AS);
1867 		show_addresses = GPOINTER_TO_INT (e_contact_get (
1868 			priv->contact, E_CONTACT_LIST_SHOW_ADDRESSES));
1869 
1870 		if (file_as == NULL)
1871 			file_as = "";
1872 
1873 		gtk_entry_set_text (
1874 			GTK_ENTRY (WIDGET (LIST_NAME_ENTRY)), file_as);
1875 
1876 		gtk_toggle_button_set_active (
1877 			GTK_TOGGLE_BUTTON (WIDGET (CHECK_BUTTON)),
1878 			!show_addresses);
1879 
1880 		e_contact_list_model_remove_all (
1881 			E_CONTACT_LIST_MODEL (priv->model));
1882 
1883 		e_destination_set_name (list_dest, file_as);
1884 		e_destination_set_contact (list_dest, priv->contact, 0);
1885 
1886 		dests = e_destination_list_get_root_dests (list_dest);
1887 		for (dest = dests; dest; dest = dest->next) {
1888 			GtkTreePath *path;
1889 			path = e_contact_list_model_add_destination (
1890 				E_CONTACT_LIST_MODEL (priv->model),
1891 				dest->data, NULL, TRUE);
1892 			gtk_tree_path_free (path);
1893 		}
1894 
1895 		g_object_unref (list_dest);
1896 
1897 		gtk_tree_view_expand_all (GTK_TREE_VIEW (WIDGET (TREE_VIEW)));
1898 	}
1899 
1900 	if (priv->book_client != NULL) {
1901 		e_source_combo_box_set_active (
1902 			E_SOURCE_COMBO_BOX (WIDGET (SOURCE_MENU)),
1903 			e_client_get_source (E_CLIENT (priv->book_client)));
1904 		gtk_widget_set_sensitive (
1905 			WIDGET (SOURCE_MENU), priv->is_new_list);
1906 	}
1907 
1908 	priv->changed = FALSE;
1909 	contact_list_editor_update (editor);
1910 
1911 	g_object_notify (G_OBJECT (editor), "contact");
1912 
1913 }
1914 
1915 gboolean
1916 e_contact_list_editor_get_is_new_list (EContactListEditor *editor)
1917 {
1918 	g_return_val_if_fail (E_IS_CONTACT_LIST_EDITOR (editor), FALSE);
1919 
1920 	return editor->priv->is_new_list;
1921 }
1922 
1923 void
1924 e_contact_list_editor_set_is_new_list (EContactListEditor *editor,
1925                                        gboolean is_new_list)
1926 {
1927 
1928 	g_return_if_fail (E_IS_CONTACT_LIST_EDITOR (editor));
1929 
1930 	if (editor->priv->is_new_list == is_new_list)
1931 		return;
1932 
1933 	editor->priv->is_new_list = is_new_list;
1934 	contact_list_editor_update (editor);
1935 
1936 	g_object_notify (G_OBJECT (editor), "is_new_list");
1937 }
1938 
1939 gboolean
1940 e_contact_list_editor_get_editable (EContactListEditor *editor)
1941 {
1942 	g_return_val_if_fail (E_IS_CONTACT_LIST_EDITOR (editor), FALSE);
1943 
1944 	return editor->priv->editable;
1945 }
1946 
1947 void
1948 e_contact_list_editor_set_editable (EContactListEditor *editor,
1949                                     gboolean editable)
1950 {
1951 	g_return_if_fail (E_IS_CONTACT_LIST_EDITOR (editor));
1952 
1953 	if (editor->priv->editable == editable)
1954 		return;
1955 
1956 	editor->priv->editable = editable;
1957 	contact_list_editor_update (editor);
1958 
1959 	g_object_notify (G_OBJECT (editor), "editable");
1960 }