1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /* e-destination-store.c - EDestination store with GtkTreeModel interface.
4  *
5  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * Authors: Hans Petter Jansson <hpj@novell.com>
20  */
21 
22 #include "evolution-config.h"
23 
24 #include <string.h>
25 #include <glib/gi18n-lib.h>
26 
27 #include "e-destination-store.h"
28 
29 #define ITER_IS_VALID(destination_store, iter) \
30 	((iter)->stamp == (destination_store)->priv->stamp)
31 #define ITER_GET(iter) \
32 	GPOINTER_TO_INT (iter->user_data)
33 #define ITER_SET(destination_store, iter, index) \
34 	G_STMT_START { \
35 	(iter)->stamp = (destination_store)->priv->stamp; \
36 	(iter)->user_data = GINT_TO_POINTER (index); \
37 	} G_STMT_END
38 
39 #define E_DESTINATION_STORE_GET_PRIVATE(obj) \
40 	(G_TYPE_INSTANCE_GET_PRIVATE \
41 	((obj), E_TYPE_DESTINATION_STORE, EDestinationStorePrivate))
42 
43 struct _EDestinationStorePrivate {
44 	GPtrArray *destinations;
45 	gint stamp;
46 };
47 
48 static GType column_types[E_DESTINATION_STORE_NUM_COLUMNS];
49 
50 static void e_destination_store_tree_model_init (GtkTreeModelIface *iface);
51 
52 G_DEFINE_TYPE_EXTENDED (
53 	EDestinationStore, e_destination_store, G_TYPE_OBJECT, 0,
54 	G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, e_destination_store_tree_model_init);
55 	column_types[E_DESTINATION_STORE_COLUMN_NAME]    = G_TYPE_STRING;
56 	column_types[E_DESTINATION_STORE_COLUMN_EMAIL]   = G_TYPE_STRING;
57 	column_types[E_DESTINATION_STORE_COLUMN_ADDRESS] = G_TYPE_STRING;
58 )
59 
60 static GtkTreeModelFlags e_destination_store_get_flags       (GtkTreeModel       *tree_model);
61 static gint         e_destination_store_get_n_columns   (GtkTreeModel       *tree_model);
62 static GType        e_destination_store_get_column_type (GtkTreeModel       *tree_model,
63 							 gint                index);
64 static gboolean     e_destination_store_get_iter        (GtkTreeModel       *tree_model,
65 							 GtkTreeIter        *iter,
66 							 GtkTreePath        *path);
67 static void         e_destination_store_get_value       (GtkTreeModel       *tree_model,
68 							 GtkTreeIter        *iter,
69 							 gint                column,
70 							 GValue             *value);
71 static gboolean     e_destination_store_iter_next       (GtkTreeModel       *tree_model,
72 							 GtkTreeIter        *iter);
73 static gboolean     e_destination_store_iter_children   (GtkTreeModel       *tree_model,
74 							 GtkTreeIter        *iter,
75 							 GtkTreeIter        *parent);
76 static gboolean     e_destination_store_iter_has_child  (GtkTreeModel       *tree_model,
77 							 GtkTreeIter        *iter);
78 static gint         e_destination_store_iter_n_children (GtkTreeModel       *tree_model,
79 							 GtkTreeIter        *iter);
80 static gboolean     e_destination_store_iter_nth_child  (GtkTreeModel       *tree_model,
81 							 GtkTreeIter        *iter,
82 							 GtkTreeIter        *parent,
83 							 gint                n);
84 static gboolean     e_destination_store_iter_parent     (GtkTreeModel       *tree_model,
85 							 GtkTreeIter        *iter,
86 							 GtkTreeIter        *child);
87 
88 static void destination_changed (EDestinationStore *destination_store, EDestination *destination);
89 static void stop_destination    (EDestinationStore *destination_store, EDestination *destination);
90 
91 static void
destination_store_dispose(GObject * object)92 destination_store_dispose (GObject *object)
93 {
94 	EDestinationStorePrivate *priv;
95 	gint ii;
96 
97 	priv = E_DESTINATION_STORE_GET_PRIVATE (object);
98 
99 	for (ii = 0; ii < priv->destinations->len; ii++) {
100 		EDestination *destination;
101 
102 		destination = g_ptr_array_index (priv->destinations, ii);
103 		stop_destination (E_DESTINATION_STORE (object), destination);
104 		g_object_unref (destination);
105 	}
106 	g_ptr_array_set_size (priv->destinations, 0);
107 
108 	/* Chain up to parent's dispose() method. */
109 	G_OBJECT_CLASS (e_destination_store_parent_class)->dispose (object);
110 }
111 
112 static void
destination_store_finalize(GObject * object)113 destination_store_finalize (GObject *object)
114 {
115 	EDestinationStorePrivate *priv;
116 
117 	priv = E_DESTINATION_STORE_GET_PRIVATE (object);
118 
119 	g_ptr_array_free (priv->destinations, TRUE);
120 
121 	/* Chain up to parent's finalize() method. */
122 	G_OBJECT_CLASS (e_destination_store_parent_class)->finalize (object);
123 }
124 
125 static void
e_destination_store_class_init(EDestinationStoreClass * class)126 e_destination_store_class_init (EDestinationStoreClass *class)
127 {
128 	GObjectClass *object_class;
129 
130 	g_type_class_add_private (class, sizeof (EDestinationStorePrivate));
131 
132 	object_class = G_OBJECT_CLASS (class);
133 	object_class->dispose = destination_store_dispose;
134 	object_class->finalize = destination_store_finalize;
135 }
136 
137 static void
e_destination_store_tree_model_init(GtkTreeModelIface * iface)138 e_destination_store_tree_model_init (GtkTreeModelIface *iface)
139 {
140 	iface->get_flags = e_destination_store_get_flags;
141 	iface->get_n_columns = e_destination_store_get_n_columns;
142 	iface->get_column_type = e_destination_store_get_column_type;
143 	iface->get_iter = e_destination_store_get_iter;
144 	iface->get_path = e_destination_store_get_path;
145 	iface->get_value = e_destination_store_get_value;
146 	iface->iter_next = e_destination_store_iter_next;
147 	iface->iter_children = e_destination_store_iter_children;
148 	iface->iter_has_child = e_destination_store_iter_has_child;
149 	iface->iter_n_children = e_destination_store_iter_n_children;
150 	iface->iter_nth_child = e_destination_store_iter_nth_child;
151 	iface->iter_parent = e_destination_store_iter_parent;
152 }
153 
154 static void
e_destination_store_init(EDestinationStore * destination_store)155 e_destination_store_init (EDestinationStore *destination_store)
156 {
157 	destination_store->priv =
158 		E_DESTINATION_STORE_GET_PRIVATE (destination_store);
159 
160 	destination_store->priv->destinations = g_ptr_array_new ();
161 	destination_store->priv->stamp = g_random_int ();
162 }
163 
164 /**
165  * e_destination_store_new:
166  *
167  * Creates a new #EDestinationStore.
168  *
169  * Returns: A new #EDestinationStore.
170  **/
171 EDestinationStore *
e_destination_store_new(void)172 e_destination_store_new (void)
173 {
174 	return g_object_new (E_TYPE_DESTINATION_STORE, NULL);
175 }
176 
177 /* ------------------ *
178  * Row update helpers *
179  * ------------------ */
180 
181 static void
row_deleted(EDestinationStore * destination_store,gint n)182 row_deleted (EDestinationStore *destination_store,
183              gint n)
184 {
185 	GtkTreePath *path;
186 
187 	path = gtk_tree_path_new ();
188 	gtk_tree_path_append_index (path, n);
189 	gtk_tree_model_row_deleted (GTK_TREE_MODEL (destination_store), path);
190 	gtk_tree_path_free (path);
191 }
192 
193 static void
row_inserted(EDestinationStore * destination_store,gint n)194 row_inserted (EDestinationStore *destination_store,
195               gint n)
196 {
197 	GtkTreePath *path;
198 	GtkTreeIter  iter;
199 
200 	path = gtk_tree_path_new ();
201 	gtk_tree_path_append_index (path, n);
202 
203 	if (gtk_tree_model_get_iter (GTK_TREE_MODEL (destination_store), &iter, path))
204 		gtk_tree_model_row_inserted (GTK_TREE_MODEL (destination_store), path, &iter);
205 
206 	gtk_tree_path_free (path);
207 }
208 
209 static void
row_changed(EDestinationStore * destination_store,gint n)210 row_changed (EDestinationStore *destination_store,
211              gint n)
212 {
213 	GtkTreePath *path;
214 	GtkTreeIter  iter;
215 
216 	path = gtk_tree_path_new ();
217 	gtk_tree_path_append_index (path, n);
218 
219 	if (gtk_tree_model_get_iter (GTK_TREE_MODEL (destination_store), &iter, path))
220 		gtk_tree_model_row_changed (GTK_TREE_MODEL (destination_store), path, &iter);
221 
222 	gtk_tree_path_free (path);
223 }
224 
225 /* ------------------- *
226  * Destination helpers *
227  * ------------------- */
228 
229 static gint
find_destination_by_pointer(EDestinationStore * destination_store,EDestination * destination)230 find_destination_by_pointer (EDestinationStore *destination_store,
231                              EDestination *destination)
232 {
233 	GPtrArray *array;
234 	gint i;
235 
236 	array = destination_store->priv->destinations;
237 
238 	for (i = 0; i < array->len; i++) {
239 		EDestination *destination_here;
240 
241 		destination_here = g_ptr_array_index (array, i);
242 
243 		if (destination_here == destination)
244 			return i;
245 	}
246 
247 	return -1;
248 }
249 
250 static gint
find_destination_by_email(EDestinationStore * destination_store,EDestination * destination)251 find_destination_by_email (EDestinationStore *destination_store,
252                            EDestination *destination)
253 {
254 	GPtrArray *array;
255 	gint i;
256 	const gchar *e_mail = e_destination_get_email (destination);
257 
258 	array = destination_store->priv->destinations;
259 
260 	for (i = 0; i < array->len; i++) {
261 		EDestination *destination_here;
262 		const gchar *mail;
263 
264 		destination_here = g_ptr_array_index (array, i);
265 		mail = e_destination_get_email (destination_here);
266 
267 		if (g_str_equal (e_mail, mail))
268 			return i;
269 	}
270 
271 	return -1;
272 }
273 
274 static void
start_destination(EDestinationStore * destination_store,EDestination * destination)275 start_destination (EDestinationStore *destination_store,
276                    EDestination *destination)
277 {
278 	g_signal_connect_swapped (
279 		destination, "changed",
280 		G_CALLBACK (destination_changed), destination_store);
281 }
282 
283 static void
stop_destination(EDestinationStore * destination_store,EDestination * destination)284 stop_destination (EDestinationStore *destination_store,
285                   EDestination *destination)
286 {
287 	g_signal_handlers_disconnect_matched (
288 		destination, G_SIGNAL_MATCH_DATA,
289 		0, 0, NULL, NULL, destination_store);
290 }
291 
292 /* --------------- *
293  * Signal handlers *
294  * --------------- */
295 
296 static void
destination_changed(EDestinationStore * destination_store,EDestination * destination)297 destination_changed (EDestinationStore *destination_store,
298                      EDestination *destination)
299 {
300 	gint n;
301 
302 	n = find_destination_by_pointer (destination_store, destination);
303 	if (n < 0) {
304 		g_warning ("EDestinationStore got change from unknown EDestination!");
305 		return;
306 	}
307 
308 	row_changed (destination_store, n);
309 }
310 
311 /* --------------------- *
312  * EDestinationStore API *
313  * --------------------- */
314 
315 /**
316  * e_destination_store_get_destination:
317  * @destination_store: an #EDestinationStore
318  * @iter: a #GtkTreeIter
319  *
320  * Gets the #EDestination from @destination_store at @iter.
321  *
322  * Returns: An #EDestination.
323  **/
324 EDestination *
e_destination_store_get_destination(EDestinationStore * destination_store,GtkTreeIter * iter)325 e_destination_store_get_destination (EDestinationStore *destination_store,
326                                      GtkTreeIter *iter)
327 {
328 	GPtrArray *array;
329 	gint index;
330 
331 	g_return_val_if_fail (E_IS_DESTINATION_STORE (destination_store), NULL);
332 	g_return_val_if_fail (ITER_IS_VALID (destination_store, iter), NULL);
333 
334 	array = destination_store->priv->destinations;
335 	index = ITER_GET (iter);
336 
337 	return g_ptr_array_index (array, index);
338 }
339 
340 /**
341  * e_destination_store_list_destinations:
342  * @destination_store: an #EDestinationStore
343  *
344  * Gets a list of all the #EDestinations in @destination_store.
345  *
346  * Returns: A #GList of pointers to #EDestination. The list is owned
347  * by the caller, but the #EDestination elements aren't.
348  **/
349 GList *
e_destination_store_list_destinations(EDestinationStore * destination_store)350 e_destination_store_list_destinations (EDestinationStore *destination_store)
351 {
352 	GList *destination_list = NULL;
353 	GPtrArray *array;
354 	gint   i;
355 
356 	g_return_val_if_fail (E_IS_DESTINATION_STORE (destination_store), NULL);
357 
358 	array = destination_store->priv->destinations;
359 
360 	for (i = 0; i < array->len; i++) {
361 		EDestination *destination;
362 
363 		destination = g_ptr_array_index (array, i);
364 		destination_list = g_list_prepend (destination_list, destination);
365 	}
366 
367 	destination_list = g_list_reverse (destination_list);
368 
369 	return destination_list;
370 }
371 
372 /**
373  * e_destination_store_insert_destination:
374  * @destination_store: an #EDestinationStore
375  * @index: the index at which to insert
376  * @destination: an #EDestination to insert
377  *
378  * Inserts @destination into @destination_store at the position
379  * indicated by @index. @destination_store will ref @destination.
380  **/
381 void
e_destination_store_insert_destination(EDestinationStore * destination_store,gint index,EDestination * destination)382 e_destination_store_insert_destination (EDestinationStore *destination_store,
383                                         gint index,
384                                         EDestination *destination)
385 {
386 	GPtrArray *array;
387 
388 	g_return_if_fail (E_IS_DESTINATION_STORE (destination_store));
389 	g_return_if_fail (index >= 0);
390 
391 	if (find_destination_by_pointer (destination_store, destination) >= 0) {
392 		g_warning ("Same destination added more than once to EDestinationStore!");
393 		return;
394 	}
395 
396 	g_object_ref (destination);
397 
398 	array = destination_store->priv->destinations;
399 	index = MIN (index, array->len);
400 
401 	g_ptr_array_set_size (array, array->len + 1);
402 
403 	if (array->len - 1 - index > 0) {
404 		memmove (
405 			array->pdata + index + 1,
406 			array->pdata + index,
407 			(array->len - 1 - index) * sizeof (gpointer));
408 	}
409 
410 	array->pdata[index] = destination;
411 	start_destination (destination_store, destination);
412 	row_inserted (destination_store, index);
413 }
414 
415 /**
416  * e_destination_store_append_destination:
417  * @destination_store: an #EDestinationStore
418  * @destination: an #EDestination
419  *
420  * Appends @destination to the list of destinations in @destination_store.
421  * @destination_store will ref @destination.
422  **/
423 void
e_destination_store_append_destination(EDestinationStore * destination_store,EDestination * destination)424 e_destination_store_append_destination (EDestinationStore *destination_store,
425                                         EDestination *destination)
426 {
427 	GPtrArray *array;
428 
429 	g_return_if_fail (E_IS_DESTINATION_STORE (destination_store));
430 
431 	if (find_destination_by_email (destination_store, destination) >= 0 && !e_destination_is_evolution_list (destination)) {
432 		g_warning ("Same destination added more than once to EDestinationStore!");
433 		return;
434 	}
435 
436 	array = destination_store->priv->destinations;
437 	g_object_ref (destination);
438 
439 	g_ptr_array_add (array, destination);
440 	start_destination (destination_store, destination);
441 	row_inserted (destination_store, array->len - 1);
442 }
443 
444 /**
445  * e_destination_store_remove_destination:
446  * @destination_store: an #EDestinationStore
447  * @destination: an #EDestination to remove
448  *
449  * Removes @destination from @destination_store. @destination_store will
450  * unref @destination.
451  **/
452 void
e_destination_store_remove_destination(EDestinationStore * destination_store,EDestination * destination)453 e_destination_store_remove_destination (EDestinationStore *destination_store,
454                                         EDestination *destination)
455 {
456 	GPtrArray *array;
457 	gint n;
458 
459 	g_return_if_fail (E_IS_DESTINATION_STORE (destination_store));
460 
461 	n = find_destination_by_pointer (destination_store, destination);
462 	if (n < 0) {
463 		g_warning ("Tried to remove unknown destination from EDestinationStore!");
464 		return;
465 	}
466 
467 	stop_destination (destination_store, destination);
468 	g_object_unref (destination);
469 
470 	array = destination_store->priv->destinations;
471 	g_ptr_array_remove_index (array, n);
472 	row_deleted (destination_store, n);
473 }
474 
475 void
e_destination_store_remove_destination_nth(EDestinationStore * destination_store,gint n)476 e_destination_store_remove_destination_nth (EDestinationStore *destination_store,
477                                             gint n)
478 {
479 	EDestination *destination;
480 	GPtrArray *array;
481 
482 	g_return_if_fail (n >= 0);
483 
484 	array = destination_store->priv->destinations;
485 	destination = g_ptr_array_index (array, n);
486 	stop_destination (destination_store, destination);
487 	g_object_unref (destination);
488 
489 	g_ptr_array_remove_index (array, n);
490 	row_deleted (destination_store, n);
491 }
492 
493 guint
e_destination_store_get_destination_count(EDestinationStore * destination_store)494 e_destination_store_get_destination_count (EDestinationStore *destination_store)
495 {
496 	return destination_store->priv->destinations->len;
497 }
498 
499 /* ---------------- *
500  * GtkTreeModel API *
501  * ---------------- */
502 
503 static GtkTreeModelFlags
e_destination_store_get_flags(GtkTreeModel * tree_model)504 e_destination_store_get_flags (GtkTreeModel *tree_model)
505 {
506 	g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), 0);
507 
508 	return GTK_TREE_MODEL_LIST_ONLY;
509 }
510 
511 static gint
e_destination_store_get_n_columns(GtkTreeModel * tree_model)512 e_destination_store_get_n_columns (GtkTreeModel *tree_model)
513 {
514 	g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), 0);
515 
516 	return E_CONTACT_FIELD_LAST;
517 }
518 
519 static GType
e_destination_store_get_column_type(GtkTreeModel * tree_model,gint index)520 e_destination_store_get_column_type (GtkTreeModel *tree_model,
521                                      gint index)
522 {
523 	g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), G_TYPE_INVALID);
524 	g_return_val_if_fail (index >= 0 && index < E_DESTINATION_STORE_NUM_COLUMNS, G_TYPE_INVALID);
525 
526 	return column_types[index];
527 }
528 
529 static gboolean
e_destination_store_get_iter(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreePath * path)530 e_destination_store_get_iter (GtkTreeModel *tree_model,
531                               GtkTreeIter *iter,
532                               GtkTreePath *path)
533 {
534 	EDestinationStore *destination_store;
535 	GPtrArray *array;
536 	gint index;
537 
538 	g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), FALSE);
539 	g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
540 
541 	destination_store = E_DESTINATION_STORE (tree_model);
542 
543 	index = gtk_tree_path_get_indices (path)[0];
544 	array = destination_store->priv->destinations;
545 
546 	if (index >= array->len)
547 		return FALSE;
548 
549 	ITER_SET (destination_store, iter, index);
550 	return TRUE;
551 }
552 
553 GtkTreePath *
e_destination_store_get_path(GtkTreeModel * tree_model,GtkTreeIter * iter)554 e_destination_store_get_path (GtkTreeModel *tree_model,
555                               GtkTreeIter *iter)
556 {
557 	EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
558 	GtkTreePath       *path;
559 	gint               index;
560 
561 	g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), NULL);
562 	g_return_val_if_fail (ITER_IS_VALID (destination_store, iter), NULL);
563 
564 	index = ITER_GET (iter);
565 	path = gtk_tree_path_new ();
566 	gtk_tree_path_append_index (path, index);
567 
568 	return path;
569 }
570 
571 static gboolean
e_destination_store_iter_next(GtkTreeModel * tree_model,GtkTreeIter * iter)572 e_destination_store_iter_next (GtkTreeModel *tree_model,
573                                GtkTreeIter *iter)
574 {
575 	EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
576 	gint           index;
577 
578 	g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), FALSE);
579 	g_return_val_if_fail (ITER_IS_VALID (destination_store, iter), FALSE);
580 
581 	index = ITER_GET (iter);
582 
583 	if (index + 1 < destination_store->priv->destinations->len) {
584 		ITER_SET (destination_store, iter, index + 1);
585 		return TRUE;
586 	}
587 
588 	return FALSE;
589 }
590 
591 static gboolean
e_destination_store_iter_children(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent)592 e_destination_store_iter_children (GtkTreeModel *tree_model,
593                                    GtkTreeIter *iter,
594                                    GtkTreeIter *parent)
595 {
596 	EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
597 
598 	g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), FALSE);
599 
600 	/* This is a list, nodes have no children. */
601 	if (parent)
602 		return FALSE;
603 
604 	/* But if parent == NULL we return the list itself as children of the root. */
605 	if (destination_store->priv->destinations->len <= 0)
606 		return FALSE;
607 
608 	ITER_SET (destination_store, iter, 0);
609 	return TRUE;
610 }
611 
612 static gboolean
e_destination_store_iter_has_child(GtkTreeModel * tree_model,GtkTreeIter * iter)613 e_destination_store_iter_has_child (GtkTreeModel *tree_model,
614                                     GtkTreeIter *iter)
615 {
616 	g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), FALSE);
617 
618 	if (iter == NULL)
619 		return TRUE;
620 
621 	return FALSE;
622 }
623 
624 static gint
e_destination_store_iter_n_children(GtkTreeModel * tree_model,GtkTreeIter * iter)625 e_destination_store_iter_n_children (GtkTreeModel *tree_model,
626                                      GtkTreeIter *iter)
627 {
628 	EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
629 
630 	g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), -1);
631 
632 	if (iter == NULL)
633 		return destination_store->priv->destinations->len;
634 
635 	g_return_val_if_fail (ITER_IS_VALID (destination_store, iter), -1);
636 	return 0;
637 }
638 
639 static gboolean
e_destination_store_iter_nth_child(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent,gint n)640 e_destination_store_iter_nth_child (GtkTreeModel *tree_model,
641                                     GtkTreeIter *iter,
642                                     GtkTreeIter *parent,
643                                     gint n)
644 {
645 	EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
646 
647 	g_return_val_if_fail (E_IS_DESTINATION_STORE (tree_model), FALSE);
648 
649 	if (parent)
650 		return FALSE;
651 
652 	if (n < destination_store->priv->destinations->len) {
653 		ITER_SET (destination_store, iter, n);
654 		return TRUE;
655 	}
656 
657 	return FALSE;
658 }
659 
660 static gboolean
e_destination_store_iter_parent(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * child)661 e_destination_store_iter_parent (GtkTreeModel *tree_model,
662                                  GtkTreeIter *iter,
663                                  GtkTreeIter *child)
664 {
665 	return FALSE;
666 }
667 
668 static void
e_destination_store_get_value(GtkTreeModel * tree_model,GtkTreeIter * iter,gint column,GValue * value)669 e_destination_store_get_value (GtkTreeModel *tree_model,
670                                GtkTreeIter *iter,
671                                gint column,
672                                GValue *value)
673 {
674 	EDestinationStore *destination_store = E_DESTINATION_STORE (tree_model);
675 	EDestination *destination;
676 	GString *string_new;
677 	EContact *contact;
678 	GPtrArray *array;
679 	const gchar *string;
680 	gint row;
681 
682 	g_return_if_fail (E_IS_DESTINATION_STORE (tree_model));
683 	g_return_if_fail (column < E_DESTINATION_STORE_NUM_COLUMNS);
684 	g_return_if_fail (ITER_IS_VALID (destination_store, iter));
685 
686 	g_value_init (value, column_types[column]);
687 
688 	array = destination_store->priv->destinations;
689 
690 	row = ITER_GET (iter);
691 	if (row >= array->len)
692 		return;
693 
694 	destination = g_ptr_array_index (array, row);
695 	g_return_if_fail (destination);
696 
697 	switch (column) {
698 		case E_DESTINATION_STORE_COLUMN_NAME:
699 			string = e_destination_get_name (destination);
700 			g_value_set_string (value, string);
701 			break;
702 
703 		case E_DESTINATION_STORE_COLUMN_EMAIL:
704 			string = e_destination_get_email (destination);
705 			g_value_set_string (value, string);
706 			break;
707 
708 		case E_DESTINATION_STORE_COLUMN_ADDRESS:
709 			contact = e_destination_get_contact (destination);
710 			if (contact && E_IS_CONTACT (contact)) {
711 				if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
712 					string = e_destination_get_name (destination);
713 					string_new = g_string_new (string);
714 					g_string_append (string_new, " mailing list");
715 					g_value_set_string (value, string_new->str);
716 					g_string_free (string_new, TRUE);
717 				}
718 				else {
719 					string = e_destination_get_address (destination);
720 					g_value_set_string (value, string);
721 				}
722 			}
723 			else {
724 				string = e_destination_get_address (destination);
725 				g_value_set_string (value, string);
726 
727 			}
728 			break;
729 
730 		default:
731 			g_warn_if_reached ();
732 			break;
733 	}
734 }
735 
736 /**
737  * e_destination_store_get_stamp:
738  * @destination_store: an #EDestinationStore
739  *
740  * Since: 2.32
741  **/
742 gint
e_destination_store_get_stamp(EDestinationStore * destination_store)743 e_destination_store_get_stamp (EDestinationStore *destination_store)
744 {
745 	g_return_val_if_fail (E_IS_DESTINATION_STORE (destination_store), 0);
746 
747 	return destination_store->priv->stamp;
748 }
749