1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* e-contact-store.c - Contacts store with GtkTreeModel interface.
5 * Copyright (C) 2004 Novell, Inc.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * Authors: Hans Petter Jansson <hpj@novell.com>
28 #include <gtk/gtktreemodel.h>
29 #include <gtk/gtksignal.h>
30 #include <gtk/gtktreednd.h>
31 #include <glib/gi18n-lib.h>
32 #include "e-contact-store.h"
34 #define ITER_IS_VALID(contact_store, iter) ((iter)->stamp == (contact_store)->stamp)
35 #define ITER_GET(iter) GPOINTER_TO_INT (iter->user_data)
36 #define ITER_SET(contact_store, iter, index) \
38 (iter)->stamp = (contact_store)->stamp; \
39 (iter)->user_data = GINT_TO_POINTER (index); \
42 static void e_contact_store_init (EContactStore *contact_store);
43 static void e_contact_store_class_init (EContactStoreClass *class);
44 static void e_contact_store_tree_model_init (GtkTreeModelIface *iface);
45 static void e_contact_store_finalize (GObject *object);
46 static GtkTreeModelFlags e_contact_store_get_flags (GtkTreeModel *tree_model);
47 static gint e_contact_store_get_n_columns (GtkTreeModel *tree_model);
48 static GType e_contact_store_get_column_type (GtkTreeModel *tree_model,
50 static gboolean e_contact_store_get_iter (GtkTreeModel *tree_model,
53 static GtkTreePath *e_contact_store_get_path (GtkTreeModel *tree_model,
55 static void e_contact_store_get_value (GtkTreeModel *tree_model,
59 static gboolean e_contact_store_iter_next (GtkTreeModel *tree_model,
61 static gboolean e_contact_store_iter_children (GtkTreeModel *tree_model,
64 static gboolean e_contact_store_iter_has_child (GtkTreeModel *tree_model,
66 static gint e_contact_store_iter_n_children (GtkTreeModel *tree_model,
68 static gboolean e_contact_store_iter_nth_child (GtkTreeModel *tree_model,
72 static gboolean e_contact_store_iter_parent (GtkTreeModel *tree_model,
83 EBookView *book_view_pending;
84 GPtrArray *contacts_pending;
88 static void free_contact_ptrarray (GPtrArray *contacts);
89 static void clear_contact_source (EContactStore *contact_store, ContactSource *source);
90 static void stop_view (EContactStore *contact_store, EBookView *view);
92 /* ------------------ *
93 * Class/object setup *
94 * ------------------ */
96 static GObjectClass *parent_class = NULL;
99 e_contact_store_get_type (void)
101 static GType contact_store_type = 0;
103 if (!contact_store_type) {
104 static const GTypeInfo contact_store_info =
106 sizeof (EContactStoreClass),
107 NULL, /* base_init */
108 NULL, /* base_finalize */
109 (GClassInitFunc) e_contact_store_class_init,
110 NULL, /* class_finalize */
111 NULL, /* class_data */
112 sizeof (EContactStore),
114 (GInstanceInitFunc) e_contact_store_init,
117 static const GInterfaceInfo tree_model_info =
119 (GInterfaceInitFunc) e_contact_store_tree_model_init,
124 contact_store_type = g_type_register_static (G_TYPE_OBJECT, "EContactStore",
125 &contact_store_info, 0);
126 g_type_add_interface_static (contact_store_type,
131 return contact_store_type;
135 e_contact_store_class_init (EContactStoreClass *class)
137 GObjectClass *object_class;
139 parent_class = g_type_class_peek_parent (class);
140 object_class = (GObjectClass *) class;
142 object_class->finalize = e_contact_store_finalize;
146 e_contact_store_tree_model_init (GtkTreeModelIface *iface)
148 iface->get_flags = e_contact_store_get_flags;
149 iface->get_n_columns = e_contact_store_get_n_columns;
150 iface->get_column_type = e_contact_store_get_column_type;
151 iface->get_iter = e_contact_store_get_iter;
152 iface->get_path = e_contact_store_get_path;
153 iface->get_value = e_contact_store_get_value;
154 iface->iter_next = e_contact_store_iter_next;
155 iface->iter_children = e_contact_store_iter_children;
156 iface->iter_has_child = e_contact_store_iter_has_child;
157 iface->iter_n_children = e_contact_store_iter_n_children;
158 iface->iter_nth_child = e_contact_store_iter_nth_child;
159 iface->iter_parent = e_contact_store_iter_parent;
163 e_contact_store_init (EContactStore *contact_store)
165 contact_store->stamp = g_random_int ();
166 contact_store->query = NULL;
167 contact_store->contact_sources = g_array_new (FALSE, FALSE, sizeof (ContactSource));
171 e_contact_store_finalize (GObject *object)
173 EContactStore *contact_store = E_CONTACT_STORE (object);
176 /* Free sources and cached contacts */
178 for (i = 0; i < contact_store->contact_sources->len; i++) {
179 ContactSource *source = &g_array_index (contact_store->contact_sources, ContactSource, i);
181 clear_contact_source (contact_store, source);
183 free_contact_ptrarray (source->contacts);
184 g_object_unref (source->book);
187 g_array_free (contact_store->contact_sources, TRUE);
188 if (contact_store->query)
189 e_book_query_unref (contact_store->query);
191 if (G_OBJECT_CLASS (parent_class)->finalize)
192 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
196 * e_contact_store_new:
198 * Creates a new #EContactStore.
200 * Return value: A new #EContactStore.
203 e_contact_store_new (void)
205 return E_CONTACT_STORE (g_object_new (E_TYPE_CONTACT_STORE, NULL));
208 /* ------------------ *
209 * Row update helpers *
210 * ------------------ */
213 row_deleted (EContactStore *contact_store, gint n)
217 path = gtk_tree_path_new ();
218 gtk_tree_path_append_index (path, n);
219 gtk_tree_model_row_deleted (GTK_TREE_MODEL (contact_store), path);
220 gtk_tree_path_free (path);
224 row_inserted (EContactStore *contact_store, gint n)
229 path = gtk_tree_path_new ();
230 gtk_tree_path_append_index (path, n);
232 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (contact_store), &iter, path))
233 gtk_tree_model_row_inserted (GTK_TREE_MODEL (contact_store), path, &iter);
235 gtk_tree_path_free (path);
239 row_changed (EContactStore *contact_store, gint n)
244 path = gtk_tree_path_new ();
245 gtk_tree_path_append_index (path, n);
247 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (contact_store), &iter, path))
248 gtk_tree_model_row_changed (GTK_TREE_MODEL (contact_store), path, &iter);
250 gtk_tree_path_free (path);
253 /* ---------------------- *
254 * Contact source helpers *
255 * ---------------------- */
258 find_contact_source_by_book (EContactStore *contact_store, EBook *book)
262 for (i = 0; i < contact_store->contact_sources->len; i++) {
263 ContactSource *source;
265 source = &g_array_index (contact_store->contact_sources, ContactSource, i);
266 if (source->book == book)
274 find_contact_source_by_book_return_view(EContactStore *contact_store, EBook *book)
278 ContactSource *source = NULL;
280 for(i = 0; i < contact_store->contact_sources->len; i++) {
281 source = &g_array_index (contact_store->contact_sources, ContactSource, i);
282 if (source->book == book)
285 return source->book_view;;
289 find_contact_source_by_view (EContactStore *contact_store, EBookView *book_view)
293 for (i = 0; i < contact_store->contact_sources->len; i++) {
294 ContactSource *source;
296 source = &g_array_index (contact_store->contact_sources, ContactSource, i);
297 if (source->book_view == book_view ||
298 source->book_view_pending == book_view)
306 find_contact_source_by_offset (EContactStore *contact_store, gint offset)
310 for (i = 0; i < contact_store->contact_sources->len; i++) {
311 ContactSource *source;
313 source = &g_array_index (contact_store->contact_sources, ContactSource, i);
314 if (source->contacts->len > offset)
317 offset -= source->contacts->len;
324 find_contact_source_by_pointer (EContactStore *contact_store, ContactSource *source)
328 i = ((gchar *) source - (gchar *) contact_store->contact_sources->data) / sizeof (ContactSource);
330 if (i < 0 || i >= contact_store->contact_sources->len)
337 get_contact_source_offset (EContactStore *contact_store, gint contact_source_index)
342 g_assert (contact_source_index < contact_store->contact_sources->len);
344 for (i = 0; i < contact_source_index; i++) {
345 ContactSource *source;
347 source = &g_array_index (contact_store->contact_sources, ContactSource, i);
348 offset += source->contacts->len;
355 count_contacts (EContactStore *contact_store)
360 for (i = 0; i < contact_store->contact_sources->len; i++) {
361 ContactSource *source;
363 source = &g_array_index (contact_store->contact_sources, ContactSource, i);
364 count += source->contacts->len;
371 find_contact_by_view_and_uid (EContactStore *contact_store, EBookView *find_view, const gchar *find_uid)
374 ContactSource *source;
378 source_index = find_contact_source_by_view (contact_store, find_view);
379 if (source_index < 0)
382 source = &g_array_index (contact_store->contact_sources, ContactSource, source_index);
384 if (find_view == source->book_view)
385 contacts = source->contacts; /* Current view */
387 contacts = source->contacts_pending; /* Pending view */
389 for (i = 0; i < contacts->len; i++) {
390 EContact *contact = g_ptr_array_index (contacts, i);
391 const gchar *uid = e_contact_get_const (contact, E_CONTACT_UID);
393 if (!strcmp (find_uid, uid))
401 find_contact_by_uid (EContactStore *contact_store, const gchar *find_uid)
405 for (i = 0; i < contact_store->contact_sources->len; i++) {
406 ContactSource *source = &g_array_index (contact_store->contact_sources, ContactSource, i);
409 for (j = 0; j < source->contacts->len; j++) {
410 EContact *contact = g_ptr_array_index (source->contacts, j);
411 const gchar *uid = e_contact_get_const (contact, E_CONTACT_UID);
413 if (!strcmp (find_uid, uid))
414 return get_contact_source_offset (contact_store, i) + j;
422 get_book_at_row (EContactStore *contact_store, gint row)
424 ContactSource *source;
427 source_index = find_contact_source_by_offset (contact_store, row);
428 if (source_index < 0)
431 source = &g_array_index (contact_store->contact_sources, ContactSource, source_index);
436 get_contact_at_row (EContactStore *contact_store, gint row)
438 ContactSource *source;
442 source_index = find_contact_source_by_offset (contact_store, row);
443 if (source_index < 0)
446 source = &g_array_index (contact_store->contact_sources, ContactSource, source_index);
447 offset = get_contact_source_offset (contact_store, source_index);
450 g_assert (row < source->contacts->len);
452 return g_ptr_array_index (source->contacts, row);
456 find_contact_source_details_by_view (EContactStore *contact_store, EBookView *book_view,
457 ContactSource **contact_source, gint *offset)
461 source_index = find_contact_source_by_view (contact_store, book_view);
462 if (source_index < 0)
465 *contact_source = &g_array_index (contact_store->contact_sources, ContactSource, source_index);
466 *offset = get_contact_source_offset (contact_store, source_index);
471 /* ------------------------- *
472 * EBookView signal handlers *
473 * ------------------------- */
476 view_contacts_added (EContactStore *contact_store, const GList *contacts, EBookView *book_view)
478 ContactSource *source;
482 if (!find_contact_source_details_by_view (contact_store, book_view, &source, &offset)) {
483 g_warning ("EContactStore got 'contacts_added' signal from unknown EBookView!");
487 for (l = contacts; l; l = g_list_next (l)) {
488 EContact *contact = l->data;
490 g_object_ref (contact);
492 if (book_view == source->book_view) {
494 g_ptr_array_add (source->contacts, contact);
495 row_inserted (contact_store, offset + source->contacts->len - 1);
498 g_ptr_array_add (source->contacts_pending, contact);
504 view_contacts_removed (EContactStore *contact_store, const GList *uids, EBookView *book_view)
506 ContactSource *source;
510 if (!find_contact_source_details_by_view (contact_store, book_view, &source, &offset)) {
511 g_warning ("EContactStore got 'contacts_removed' signal from unknown EBookView!");
515 for (l = uids; l; l = g_list_next (l)) {
516 const gchar *uid = l->data;
517 gint n = find_contact_by_view_and_uid (contact_store, book_view, uid);
521 g_warning ("EContactStore got 'contacts_removed' on unknown contact!");
525 if (book_view == source->book_view) {
527 contact = g_ptr_array_index (source->contacts, n);
528 g_object_unref (contact);
529 g_ptr_array_remove_index (source->contacts, n);
530 row_deleted (contact_store, offset + n);
533 contact = g_ptr_array_index (source->contacts_pending, n);
534 g_object_unref (contact);
535 g_ptr_array_remove_index (source->contacts_pending, n);
541 view_contacts_changed (EContactStore *contact_store, const GList *contacts, EBookView *book_view)
543 GPtrArray *cached_contacts;
544 ContactSource *source;
548 if (!find_contact_source_details_by_view (contact_store, book_view, &source, &offset)) {
549 g_warning ("EContactStore got 'contacts_changed' signal from unknown EBookView!");
553 if (book_view == source->book_view)
554 cached_contacts = source->contacts;
556 cached_contacts = source->contacts_pending;
558 for (l = contacts; l; l = g_list_next (l)) {
559 EContact *cached_contact;
560 EContact *contact = l->data;
561 const gchar *uid = e_contact_get_const (contact, E_CONTACT_UID);
562 gint n = find_contact_by_view_and_uid (contact_store, book_view, uid);
565 g_warning ("EContactStore got change notification on unknown contact!");
569 cached_contact = g_ptr_array_index (cached_contacts, n);
571 /* Update cached contact */
572 if (cached_contact != contact) {
573 g_object_unref (cached_contact);
574 cached_contacts->pdata [n] = g_object_ref (contact);
577 /* Emit changes for current view only */
578 if (book_view == source->book_view)
579 row_changed (contact_store, offset + n);
584 view_sequence_complete (EContactStore *contact_store, EBookViewStatus status, EBookView *book_view)
586 ContactSource *source;
590 if (!find_contact_source_details_by_view (contact_store, book_view, &source, &offset)) {
591 g_warning ("EContactStore got 'sequence_complete' signal from unknown EBookView!");
595 /* If current view finished, do nothing */
596 if (book_view == source->book_view) {
597 stop_view (contact_store, source->book_view);
601 g_assert (book_view == source->book_view_pending);
603 /* However, if it was a pending view, calculate and emit the differences between that
604 * and the current view, and move the pending view up to current.
606 * This is O(m * n), and can be sped up with a temporary hash table if needed. */
609 for (i = 0; i < source->contacts->len; i++) {
610 EContact *old_contact = g_ptr_array_index (source->contacts, i);
611 const gchar *old_uid = e_contact_get_const (old_contact, E_CONTACT_UID);
614 result = find_contact_by_view_and_uid (contact_store, source->book_view_pending, old_uid);
616 /* Contact is not in new view; removed */
617 g_object_unref (old_contact);
618 g_ptr_array_remove_index (source->contacts, i);
619 row_deleted (contact_store, offset + i);
620 i--; /* Stay in place */
625 for (i = 0; i < source->contacts_pending->len; i++) {
626 EContact *new_contact = g_ptr_array_index (source->contacts_pending, i);
627 const gchar *new_uid = e_contact_get_const (new_contact, E_CONTACT_UID);
630 result = find_contact_by_view_and_uid (contact_store, source->book_view, new_uid);
632 /* Contact is not in old view; inserted */
633 g_ptr_array_add (source->contacts, new_contact);
634 row_inserted (contact_store, offset + source->contacts->len - 1);
636 /* Contact already in old view; drop the new one */
637 g_object_unref (new_contact);
641 /* Move pending view up to current */
642 stop_view (contact_store, source->book_view);
643 g_object_unref (source->book_view);
644 source->book_view = source->book_view_pending;
645 source->book_view_pending = NULL;
647 /* Free array of pending contacts (members have been either moved or unreffed) */
648 g_ptr_array_free (source->contacts_pending, TRUE);
649 source->contacts_pending = NULL;
652 /* --------------------- *
653 * View/Query management *
654 * --------------------- */
657 start_view (EContactStore *contact_store, EBookView *view)
659 g_signal_connect_swapped (view, "contacts_added",
660 G_CALLBACK (view_contacts_added), contact_store);
661 g_signal_connect_swapped (view, "contacts_removed",
662 G_CALLBACK (view_contacts_removed), contact_store);
663 g_signal_connect_swapped (view, "contacts_changed",
664 G_CALLBACK (view_contacts_changed), contact_store);
665 g_signal_connect_swapped (view, "sequence_complete",
666 G_CALLBACK (view_sequence_complete), contact_store);
668 e_book_view_start (view);
672 stop_view (EContactStore *contact_store, EBookView *view)
674 e_book_view_stop (view);
676 g_signal_handlers_disconnect_matched (view, G_SIGNAL_MATCH_DATA,
677 0, 0, NULL, NULL, contact_store);
681 clear_contact_ptrarray (GPtrArray *contacts)
685 for (i = 0; i < contacts->len; i++) {
686 EContact *contact = g_ptr_array_index (contacts, i);
687 g_object_unref (contact);
690 g_ptr_array_set_size (contacts, 0);
694 free_contact_ptrarray (GPtrArray *contacts)
696 clear_contact_ptrarray (contacts);
697 g_ptr_array_free (contacts, TRUE);
701 clear_contact_source (EContactStore *contact_store, ContactSource *source)
706 source_index = find_contact_source_by_pointer (contact_store, source);
707 g_assert (source_index >= 0);
709 offset = get_contact_source_offset (contact_store, source_index);
710 g_assert (offset >= 0);
712 /* Inform listeners that contacts went away */
714 if (source->contacts && source->contacts->len > 0) {
715 GtkTreePath *path = gtk_tree_path_new ();
718 gtk_tree_path_append_index (path, source->contacts->len);
720 for (i = source->contacts->len - 1; i >= 0; i--) {
721 EContact *contact = g_ptr_array_index (source->contacts, i);
723 g_object_unref (contact);
724 g_ptr_array_remove_index_fast (source->contacts, i);
726 gtk_tree_path_prev (path);
727 gtk_tree_model_row_deleted (GTK_TREE_MODEL (contact_store), path);
730 gtk_tree_path_free (path);
733 /* Free main and pending views, clear cached contacts */
735 if (source->book_view) {
736 stop_view (contact_store, source->book_view);
737 g_object_unref (source->book_view);
739 source->book_view = NULL;
742 if (source->book_view_pending) {
743 stop_view (contact_store, source->book_view_pending);
744 g_object_unref (source->book_view_pending);
745 free_contact_ptrarray (source->contacts_pending);
747 source->book_view_pending = NULL;
748 source->contacts_pending = NULL;
753 query_contact_source (EContactStore *contact_store, ContactSource *source)
757 g_assert (source->book != NULL);
759 if (!contact_store->query) {
760 clear_contact_source (contact_store, source);
764 if (!e_book_is_opened (source->book) ||
765 !e_book_get_book_view (source->book, contact_store->query, NULL, -1, &view, NULL))
768 if (source->book_view) {
769 if (source->book_view_pending) {
770 stop_view (contact_store, source->book_view_pending);
771 g_object_unref (source->book_view_pending);
772 free_contact_ptrarray (source->contacts_pending);
775 source->book_view_pending = view;
777 if (source->book_view_pending) {
778 source->contacts_pending = g_ptr_array_new ();
779 start_view (contact_store, view);
781 source->contacts_pending = NULL;
784 source->book_view = view;
786 if (source->book_view) {
787 start_view (contact_store, view);
792 /* ----------------- *
793 * EContactStore API *
794 * ----------------- */
797 * e_contact_store_get_book:
798 * @contact_store: an #EContactStore
799 * @iter: a #GtkTreeIter from @contact_store
801 * Gets the #EBook that provided the contact at @iter.
803 * Return value: An #EBook.
806 e_contact_store_get_book (EContactStore *contact_store, GtkTreeIter *iter)
810 g_return_val_if_fail (E_IS_CONTACT_STORE (contact_store), NULL);
811 g_return_val_if_fail (ITER_IS_VALID (contact_store, iter), NULL);
813 index = ITER_GET (iter);
815 return get_book_at_row (contact_store, index);
819 * e_contact_store_get_contact:
820 * @contact_store: an #EContactStore
821 * @iter: a #GtkTreeIter from @contact_store
823 * Gets the #EContact at @iter.
825 * Return value: An #EContact.
828 e_contact_store_get_contact (EContactStore *contact_store, GtkTreeIter *iter)
832 g_return_val_if_fail (E_IS_CONTACT_STORE (contact_store), NULL);
833 g_return_val_if_fail (ITER_IS_VALID (contact_store, iter), NULL);
835 index = ITER_GET (iter);
837 return get_contact_at_row (contact_store, index);
841 * e_contact_store_find_contact:
842 * @contact_store: an #EContactStore
843 * @uid: a unique contact identifier
844 * @iter: a destination #GtkTreeIter to set
846 * Sets @iter to point to the contact row matching @uid.
848 * Return value: %TRUE if the contact was found, and @iter was set. %FALSE otherwise.
851 e_contact_store_find_contact (EContactStore *contact_store, const gchar *uid,
856 g_return_val_if_fail (E_IS_CONTACT_STORE (contact_store), FALSE);
857 g_return_val_if_fail (uid != NULL, FALSE);
859 index = find_contact_by_uid (contact_store, uid);
863 ITER_SET (contact_store, iter, index);
868 * e_contact_store_get_books:
869 * @contact_store: an #EContactStore
871 * Gets the list of books that provide contacts for @contact_store.
873 * Return value: A #GList of pointers to #EBook. The caller owns the list,
877 e_contact_store_get_books (EContactStore *contact_store)
879 GList *book_list = NULL;
882 g_return_val_if_fail (E_IS_CONTACT_STORE (contact_store), NULL);
884 for (i = 0; i < contact_store->contact_sources->len; i++) {
885 ContactSource *source;
887 source = &g_array_index (contact_store->contact_sources, ContactSource, i);
888 book_list = g_list_prepend (book_list, source->book);
895 * e_contact_store_add_book:
896 * @contact_store: an #EContactStore
899 * Adds @book to the list of books that provide contacts for @contact_store.
902 e_contact_store_add_book (EContactStore *contact_store, EBook *book)
904 ContactSource source;
905 ContactSource *indexed_source;
907 g_return_if_fail (E_IS_CONTACT_STORE (contact_store));
908 g_return_if_fail (E_IS_BOOK (book));
910 if (find_contact_source_by_book (contact_store, book) >= 0) {
911 g_warning ("Same book added more than once to EContactStore!");
915 memset (&source, 0, sizeof (ContactSource));
916 source.book = g_object_ref (book);
917 source.contacts = g_ptr_array_new ();
918 g_array_append_val (contact_store->contact_sources, source);
920 indexed_source = &g_array_index (contact_store->contact_sources, ContactSource,
921 contact_store->contact_sources->len - 1);
923 query_contact_source (contact_store, indexed_source);
927 * e_contact_store_remove_book:
928 * @contact_store: an #EContactStore
931 * Removes @book from the list of books that provide contacts for @contact_store.
934 e_contact_store_remove_book (EContactStore *contact_store, EBook *book)
936 ContactSource *source;
939 g_return_if_fail (E_IS_CONTACT_STORE (contact_store));
940 g_return_if_fail (E_IS_BOOK (book));
942 source_index = find_contact_source_by_book (contact_store, book);
943 if (source_index < 0) {
944 g_warning ("Tried to remove unknown book from EContactStore!");
948 source = &g_array_index (contact_store->contact_sources, ContactSource, source_index);
949 clear_contact_source (contact_store, source);
950 free_contact_ptrarray (source->contacts);
951 g_object_unref (book);
953 g_array_remove_index (contact_store->contact_sources, source_index); /* Preserve order */
957 * e_contact_store_set_query:
958 * @contact_store: an #EContactStore
959 * @book_query: an #EBookQuery
961 * Sets @book_query to be the query used to fetch contacts from the books
962 * assigned to @contact_store.
965 e_contact_store_set_query (EContactStore *contact_store, EBookQuery *book_query)
969 g_return_if_fail (E_IS_CONTACT_STORE (contact_store));
971 if (book_query == contact_store->query)
974 if (contact_store->query)
975 e_book_query_unref (contact_store->query);
977 contact_store->query = book_query;
979 e_book_query_ref (book_query);
982 for (i = 0; i < contact_store->contact_sources->len; i++) {
983 ContactSource *contact_source;
985 contact_source = &g_array_index (contact_store->contact_sources, ContactSource, i);
986 query_contact_source (contact_store, contact_source);
991 * e_contact_store_peek_query:
992 * @contact_store: an #EContactStore
994 * Gets the query that's being used to fetch contacts from the books
995 * assigned to @contact_store.
997 * Return value: The #EBookQuery being used.
1000 e_contact_store_peek_query (EContactStore *contact_store)
1002 g_return_val_if_fail (E_IS_CONTACT_STORE (contact_store), NULL);
1004 return contact_store->query;
1007 /* ---------------- *
1008 * GtkTreeModel API *
1009 * ---------------- */
1011 static GtkTreeModelFlags
1012 e_contact_store_get_flags (GtkTreeModel *tree_model)
1014 g_return_val_if_fail (E_IS_CONTACT_STORE (tree_model), 0);
1016 return GTK_TREE_MODEL_LIST_ONLY;
1020 e_contact_store_get_n_columns (GtkTreeModel *tree_model)
1022 g_return_val_if_fail (E_IS_CONTACT_STORE (tree_model), 0);
1024 return E_CONTACT_FIELD_LAST;
1028 get_column_type (EContactStore *contact_store, gint column)
1030 const gchar *field_name;
1031 GObjectClass *contact_class;
1032 GParamSpec *param_spec;
1035 /* Silently suppress requests for columns lower than the first EContactField.
1036 * GtkTreeView automatically queries the type of all columns up to the maximum
1037 * provided, and we have to return a valid value type, so let it be a generic
1039 if (column < E_CONTACT_FIELD_FIRST) {
1040 return G_TYPE_POINTER;
1043 field_name = e_contact_field_name (column);
1044 contact_class = g_type_class_ref (E_TYPE_CONTACT);
1045 param_spec = g_object_class_find_property (contact_class, field_name);
1046 value_type = G_PARAM_SPEC_VALUE_TYPE (param_spec);
1047 g_type_class_unref (contact_class);
1053 e_contact_store_get_column_type (GtkTreeModel *tree_model,
1056 EContactStore *contact_store = E_CONTACT_STORE (tree_model);
1058 g_return_val_if_fail (E_IS_CONTACT_STORE (tree_model), G_TYPE_INVALID);
1059 g_return_val_if_fail (index >= 0 && index < E_CONTACT_FIELD_LAST, G_TYPE_INVALID);
1061 return get_column_type (contact_store, index);
1065 e_contact_store_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
1067 EContactStore *contact_store = E_CONTACT_STORE (tree_model);
1070 g_return_val_if_fail (E_IS_CONTACT_STORE (tree_model), FALSE);
1071 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
1073 index = gtk_tree_path_get_indices (path)[0];
1074 if (index >= count_contacts (contact_store))
1077 ITER_SET (contact_store, iter, index);
1081 static GtkTreePath *
1082 e_contact_store_get_path (GtkTreeModel *tree_model,
1085 EContactStore *contact_store = E_CONTACT_STORE (tree_model);
1089 g_return_val_if_fail (E_IS_CONTACT_STORE (tree_model), NULL);
1090 g_return_val_if_fail (ITER_IS_VALID (contact_store, iter), NULL);
1092 index = ITER_GET (iter);
1093 path = gtk_tree_path_new ();
1094 gtk_tree_path_append_index (path, index);
1100 e_contact_store_iter_next (GtkTreeModel *tree_model,
1103 EContactStore *contact_store = E_CONTACT_STORE (tree_model);
1106 g_return_val_if_fail (E_IS_CONTACT_STORE (tree_model), FALSE);
1107 g_return_val_if_fail (ITER_IS_VALID (contact_store, iter), FALSE);
1109 index = ITER_GET (iter);
1111 if (index + 1 < count_contacts (contact_store)) {
1112 ITER_SET (contact_store, iter, index + 1);
1120 e_contact_store_iter_children (GtkTreeModel *tree_model,
1122 GtkTreeIter *parent)
1124 EContactStore *contact_store = E_CONTACT_STORE (tree_model);
1126 g_return_val_if_fail (E_IS_CONTACT_STORE (tree_model), FALSE);
1128 /* This is a list, nodes have no children. */
1132 /* But if parent == NULL we return the list itself as children of the root. */
1133 if (count_contacts (contact_store) <= 0)
1136 ITER_SET (contact_store, iter, 0);
1141 e_contact_store_iter_has_child (GtkTreeModel *tree_model,
1144 g_return_val_if_fail (E_IS_CONTACT_STORE (tree_model), FALSE);
1153 e_contact_store_iter_n_children (GtkTreeModel *tree_model,
1156 EContactStore *contact_store = E_CONTACT_STORE (tree_model);
1158 g_return_val_if_fail (E_IS_CONTACT_STORE (tree_model), -1);
1161 return count_contacts (contact_store);
1163 g_return_val_if_fail (ITER_IS_VALID (contact_store, iter), -1);
1168 e_contact_store_iter_nth_child (GtkTreeModel *tree_model,
1170 GtkTreeIter *parent,
1173 EContactStore *contact_store = E_CONTACT_STORE (tree_model);
1175 g_return_val_if_fail (E_IS_CONTACT_STORE (tree_model), FALSE);
1180 if (n < count_contacts (contact_store)) {
1181 ITER_SET (contact_store, iter, n);
1189 e_contact_store_iter_parent (GtkTreeModel *tree_model,
1197 e_contact_store_get_value (GtkTreeModel *tree_model,
1202 EContactStore *contact_store = E_CONTACT_STORE (tree_model);
1204 const gchar *field_name;
1207 g_return_if_fail (E_IS_CONTACT_STORE (tree_model));
1208 g_return_if_fail (column < E_CONTACT_FIELD_LAST);
1209 g_return_if_fail (ITER_IS_VALID (contact_store, iter));
1211 g_value_init (value, get_column_type (contact_store, column));
1213 row = ITER_GET (iter);
1214 contact = get_contact_at_row (contact_store, row);
1215 if (!contact || column < E_CONTACT_FIELD_FIRST)
1218 field_name = e_contact_field_name (column);
1219 g_object_get_property (G_OBJECT (contact), field_name, value);