1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4 * Copyright (C) 2006 OpenedHand Ltd
5 * Copyright (C) 2009 Intel Corporation
7 * This library is free software; you can redistribute it and/or modify it under
8 * the terms of version 2.1 of the GNU Lesser General Public License as
9 * published by the Free Software Foundation.
11 * This library is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this library; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author: Ross Burton <ross@linux.intel.com>
29 #include "e-data-book-view.h"
31 #include "e-data-book.h"
32 #include "e-book-backend.h"
34 #include "e-gdbus-book-view.h"
36 #define E_DATA_BOOK_VIEW_GET_PRIVATE(obj) \
37 (G_TYPE_INSTANCE_GET_PRIVATE \
38 ((obj), E_TYPE_DATA_BOOK_VIEW, EDataBookViewPrivate))
40 /* how many items can be hold in a cache, before propagated to UI */
41 #define THRESHOLD_ITEMS 32
43 /* how long to wait until notifications are propagated to UI; in seconds */
44 #define THRESHOLD_SECONDS 2
46 struct _EDataBookViewPrivate {
47 GDBusConnection *connection;
48 EGdbusBookView *gdbus_object;
52 EBookBackend *backend;
54 EBookBackendSExp *sexp;
55 EBookClientViewFlags flags;
69 /* which fields is listener interested in */
70 GHashTable *fields_of_interest;
71 gboolean send_uids_only;
82 /* Forward Declarations */
83 static void e_data_book_view_initable_init (GInitableIface *interface);
85 G_DEFINE_TYPE_WITH_CODE (
89 G_IMPLEMENT_INTERFACE (
91 e_data_book_view_initable_init))
94 str_ic_hash (gconstpointer key)
97 const gchar *str = key;
103 for (ii = 0; str[ii] != '\0'; ii++)
104 hash = hash * 33 + g_ascii_tolower (str[ii]);
110 str_ic_equal (gconstpointer a,
113 const gchar *stra = a;
114 const gchar *strb = b;
117 if (stra == NULL && strb == NULL)
120 if (stra == NULL || strb == NULL)
123 for (ii = 0; stra[ii] != '\0' && strb[ii] != '\0'; ii++) {
124 if (g_ascii_tolower (stra[ii]) != g_ascii_tolower (strb[ii]))
128 return stra[ii] == strb[ii];
132 reset_array (GArray *array)
137 /* Free stored strings */
138 for (i = 0; i < array->len; i++) {
139 tmp = g_array_index (array, gchar *, i);
143 /* Force the array size to 0 */
144 g_array_set_size (array, 0);
148 send_pending_adds (EDataBookView *view)
150 if (view->priv->adds->len == 0)
153 e_gdbus_book_view_emit_objects_added (
154 view->priv->gdbus_object,
155 (const gchar * const *) view->priv->adds->data);
156 reset_array (view->priv->adds);
160 send_pending_changes (EDataBookView *view)
162 if (view->priv->changes->len == 0)
165 e_gdbus_book_view_emit_objects_modified (
166 view->priv->gdbus_object,
167 (const gchar * const *) view->priv->changes->data);
168 reset_array (view->priv->changes);
172 send_pending_removes (EDataBookView *view)
174 if (view->priv->removes->len == 0)
177 e_gdbus_book_view_emit_objects_removed (
178 view->priv->gdbus_object,
179 (const gchar * const *) view->priv->removes->data);
180 reset_array (view->priv->removes);
184 pending_flush_timeout_cb (gpointer data)
186 EDataBookView *view = data;
188 g_mutex_lock (&view->priv->pending_mutex);
190 view->priv->flush_id = 0;
192 send_pending_adds (view);
193 send_pending_changes (view);
194 send_pending_removes (view);
196 g_mutex_unlock (&view->priv->pending_mutex);
202 ensure_pending_flush_timeout (EDataBookView *view)
204 if (view->priv->flush_id > 0)
207 view->priv->flush_id = g_timeout_add_seconds (
208 THRESHOLD_SECONDS, pending_flush_timeout_cb, view);
212 book_destroyed_cb (gpointer data,
215 EDataBookView *view = E_DATA_BOOK_VIEW (data);
217 /* The book has just died, so unset the pointer so
218 * we don't try and remove a dead weak reference. */
219 view->priv->book = NULL;
221 /* If the view is running stop it here. */
222 if (view->priv->running) {
223 e_book_backend_stop_view (view->priv->backend, view);
224 view->priv->running = FALSE;
225 view->priv->complete = FALSE;
230 bookview_start_thread (gpointer data)
232 EDataBookView *view = data;
234 if (view->priv->running)
235 e_book_backend_start_view (view->priv->backend, view);
236 g_object_unref (view);
242 impl_DataBookView_start (EGdbusBookView *object,
243 GDBusMethodInvocation *invocation,
248 view->priv->running = TRUE;
249 view->priv->complete = FALSE;
251 thread = g_thread_new (
252 NULL, bookview_start_thread, g_object_ref (view));
253 g_thread_unref (thread);
255 e_gdbus_book_view_complete_start (object, invocation, NULL);
261 bookview_stop_thread (gpointer data)
263 EDataBookView *view = data;
265 if (!view->priv->running)
266 e_book_backend_stop_view (view->priv->backend, view);
267 g_object_unref (view);
273 impl_DataBookView_stop (EGdbusBookView *object,
274 GDBusMethodInvocation *invocation,
279 view->priv->running = FALSE;
280 view->priv->complete = FALSE;
282 thread = g_thread_new (
283 NULL, bookview_stop_thread, g_object_ref (view));
284 g_thread_unref (thread);
286 e_gdbus_book_view_complete_stop (object, invocation, NULL);
292 impl_DataBookView_setFlags (EGdbusBookView *object,
293 GDBusMethodInvocation *invocation,
294 EBookClientViewFlags flags,
297 view->priv->flags = flags;
299 e_gdbus_book_view_complete_set_flags (object, invocation, NULL);
305 impl_DataBookView_dispose (EGdbusBookView *object,
306 GDBusMethodInvocation *invocation,
309 e_gdbus_book_view_complete_dispose (object, invocation, NULL);
311 e_book_backend_stop_view (view->priv->backend, view);
312 view->priv->running = FALSE;
313 e_book_backend_remove_view (view->priv->backend, view);
315 g_object_unref (view);
321 impl_DataBookView_set_fields_of_interest (EGdbusBookView *object,
322 GDBusMethodInvocation *invocation,
323 const gchar * const *in_fields_of_interest,
328 g_return_val_if_fail (in_fields_of_interest != NULL, TRUE);
330 if (view->priv->fields_of_interest != NULL) {
331 g_hash_table_destroy (view->priv->fields_of_interest);
332 view->priv->fields_of_interest = NULL;
335 view->priv->send_uids_only = FALSE;
337 for (ii = 0; in_fields_of_interest[ii]; ii++) {
338 const gchar *field = in_fields_of_interest[ii];
343 if (strcmp (field, "x-evolution-uids-only") == 0) {
344 view->priv->send_uids_only = TRUE;
348 if (view->priv->fields_of_interest == NULL)
349 view->priv->fields_of_interest =
350 g_hash_table_new_full (
351 (GHashFunc) str_ic_hash,
352 (GEqualFunc) str_ic_equal,
353 (GDestroyNotify) g_free,
354 (GDestroyNotify) NULL);
356 g_hash_table_insert (
357 view->priv->fields_of_interest,
358 g_strdup (field), GINT_TO_POINTER (1));
361 e_gdbus_book_view_complete_set_fields_of_interest (
362 object, invocation, NULL);
368 data_book_view_set_backend (EDataBookView *view,
369 EBookBackend *backend)
371 g_return_if_fail (E_IS_BOOK_BACKEND (backend));
372 g_return_if_fail (view->priv->backend == NULL);
374 view->priv->backend = g_object_ref (backend);
378 data_book_view_set_connection (EDataBookView *view,
379 GDBusConnection *connection)
381 g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
382 g_return_if_fail (view->priv->connection == NULL);
384 view->priv->connection = g_object_ref (connection);
388 data_book_view_set_object_path (EDataBookView *view,
389 const gchar *object_path)
391 g_return_if_fail (object_path != NULL);
392 g_return_if_fail (view->priv->object_path == NULL);
394 view->priv->object_path = g_strdup (object_path);
398 data_book_view_set_sexp (EDataBookView *view,
399 EBookBackendSExp *sexp)
401 g_return_if_fail (E_IS_BOOK_BACKEND_SEXP (sexp));
402 g_return_if_fail (view->priv->sexp == NULL);
404 view->priv->sexp = g_object_ref (sexp);
408 data_book_view_set_property (GObject *object,
413 switch (property_id) {
415 data_book_view_set_backend (
416 E_DATA_BOOK_VIEW (object),
417 g_value_get_object (value));
420 case PROP_CONNECTION:
421 data_book_view_set_connection (
422 E_DATA_BOOK_VIEW (object),
423 g_value_get_object (value));
426 case PROP_OBJECT_PATH:
427 data_book_view_set_object_path (
428 E_DATA_BOOK_VIEW (object),
429 g_value_get_string (value));
433 data_book_view_set_sexp (
434 E_DATA_BOOK_VIEW (object),
435 g_value_get_object (value));
439 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
443 data_book_view_get_property (GObject *object,
448 switch (property_id) {
452 e_data_book_view_get_backend (
453 E_DATA_BOOK_VIEW (object)));
456 case PROP_CONNECTION:
459 e_data_book_view_get_connection (
460 E_DATA_BOOK_VIEW (object)));
463 case PROP_OBJECT_PATH:
466 e_data_book_view_get_object_path (
467 E_DATA_BOOK_VIEW (object)));
473 e_data_book_view_get_sexp (
474 E_DATA_BOOK_VIEW (object)));
478 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
482 data_book_view_dispose (GObject *object)
484 EDataBookViewPrivate *priv;
486 priv = E_DATA_BOOK_VIEW_GET_PRIVATE (object);
488 if (priv->connection != NULL) {
489 g_object_unref (priv->connection);
490 priv->connection = NULL;
493 if (priv->book != NULL) {
494 /* Remove the weak reference */
495 g_object_weak_unref (
496 G_OBJECT (priv->book),
497 book_destroyed_cb, object);
501 if (priv->backend != NULL) {
502 g_object_unref (priv->backend);
503 priv->backend = NULL;
506 if (priv->sexp != NULL) {
507 g_object_unref (priv->sexp);
511 g_mutex_lock (&priv->pending_mutex);
513 if (priv->flush_id > 0) {
514 g_source_remove (priv->flush_id);
518 g_mutex_unlock (&priv->pending_mutex);
520 /* Chain up to parent's dispose() method. */
521 G_OBJECT_CLASS (e_data_book_view_parent_class)->dispose (object);
525 data_book_view_finalize (GObject *object)
527 EDataBookViewPrivate *priv;
529 priv = E_DATA_BOOK_VIEW_GET_PRIVATE (object);
531 g_free (priv->object_path);
533 reset_array (priv->adds);
534 reset_array (priv->changes);
535 reset_array (priv->removes);
536 g_array_free (priv->adds, TRUE);
537 g_array_free (priv->changes, TRUE);
538 g_array_free (priv->removes, TRUE);
540 if (priv->fields_of_interest)
541 g_hash_table_destroy (priv->fields_of_interest);
543 g_mutex_clear (&priv->pending_mutex);
545 g_hash_table_destroy (priv->ids);
547 /* Chain up to parent's finalize() method. */
548 G_OBJECT_CLASS (e_data_book_view_parent_class)->finalize (object);
552 data_book_view_initable_init (GInitable *initable,
553 GCancellable *cancellable,
558 view = E_DATA_BOOK_VIEW (initable);
560 return e_gdbus_book_view_register_object (
561 view->priv->gdbus_object,
562 view->priv->connection,
563 view->priv->object_path,
568 e_data_book_view_class_init (EDataBookViewClass *class)
570 GObjectClass *object_class;
572 g_type_class_add_private (class, sizeof (EDataBookViewPrivate));
574 object_class = G_OBJECT_CLASS (class);
575 object_class->set_property = data_book_view_set_property;
576 object_class->get_property = data_book_view_get_property;
577 object_class->dispose = data_book_view_dispose;
578 object_class->finalize = data_book_view_finalize;
580 g_object_class_install_property (
583 g_param_spec_object (
586 "The backend being monitored",
589 G_PARAM_CONSTRUCT_ONLY |
590 G_PARAM_STATIC_STRINGS));
592 g_object_class_install_property (
595 g_param_spec_object (
598 "The GDBusConnection on which "
599 "to export the view interface",
600 G_TYPE_DBUS_CONNECTION,
602 G_PARAM_CONSTRUCT_ONLY |
603 G_PARAM_STATIC_STRINGS));
605 g_object_class_install_property (
608 g_param_spec_string (
611 "The object path at which to "
612 "export the view interface",
615 G_PARAM_CONSTRUCT_ONLY |
616 G_PARAM_STATIC_STRINGS));
618 g_object_class_install_property (
621 g_param_spec_object (
624 "The query expression for this view",
625 E_TYPE_BOOK_BACKEND_SEXP,
627 G_PARAM_CONSTRUCT_ONLY |
628 G_PARAM_STATIC_STRINGS));
632 e_data_book_view_initable_init (GInitableIface *interface)
634 interface->init = data_book_view_initable_init;
638 e_data_book_view_init (EDataBookView *view)
640 view->priv = E_DATA_BOOK_VIEW_GET_PRIVATE (view);
642 view->priv->flags = E_BOOK_CLIENT_VIEW_FLAGS_NOTIFY_INITIAL;
644 view->priv->gdbus_object = e_gdbus_book_view_stub_new ();
646 view->priv->gdbus_object, "handle-start",
647 G_CALLBACK (impl_DataBookView_start), view);
649 view->priv->gdbus_object, "handle-stop",
650 G_CALLBACK (impl_DataBookView_stop), view);
652 view->priv->gdbus_object, "handle-set-flags",
653 G_CALLBACK (impl_DataBookView_setFlags), view);
655 view->priv->gdbus_object, "handle-dispose",
656 G_CALLBACK (impl_DataBookView_dispose), view);
658 view->priv->gdbus_object, "handle-set-fields-of-interest",
659 G_CALLBACK (impl_DataBookView_set_fields_of_interest), view);
661 view->priv->fields_of_interest = NULL;
662 view->priv->running = FALSE;
663 view->priv->complete = FALSE;
664 g_mutex_init (&view->priv->pending_mutex);
666 /* THRESHOLD_ITEMS * 2 because we store UID and vcard */
667 view->priv->adds = g_array_sized_new (
668 TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS * 2);
669 view->priv->changes = g_array_sized_new (
670 TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS * 2);
671 view->priv->removes = g_array_sized_new (
672 TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS);
674 view->priv->ids = g_hash_table_new_full (
675 (GHashFunc) g_str_hash,
676 (GEqualFunc) g_str_equal,
677 (GDestroyNotify) g_free,
678 (GDestroyNotify) NULL);
680 view->priv->flush_id = 0;
684 * e_data_book_view_new:
685 * @book: The #EDataBook to search
686 * @sexp: The query as an #EBookBackendSExp
688 * Create a new #EDataBookView for the given #EBook, filtering on @sexp,
689 * and place it on DBus at the object path #path.
692 e_data_book_view_new (EDataBook *book,
693 EBookBackendSExp *sexp,
694 GDBusConnection *connection,
695 const gchar *object_path,
699 EBookBackend *backend;
701 g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
702 g_return_val_if_fail (E_IS_BOOK_BACKEND_SEXP (sexp), NULL);
703 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
704 g_return_val_if_fail (object_path != NULL, NULL);
706 backend = e_data_book_get_backend (book);
708 view = g_initable_new (
709 E_TYPE_DATA_BOOK_VIEW, NULL, error,
711 "connection", connection,
712 "object-path", object_path,
718 view->priv->book = book;
719 /* Attach a weak reference to the book, so
720 * if it dies the book view is destroyed too. */
722 G_OBJECT (view->priv->book),
723 book_destroyed_cb, view);
729 * e_data_book_view_get_backend:
730 * @view: an #EDataBookView
732 * Gets the backend that @view is querying.
734 * Returns: The associated #EBookBackend.
737 e_data_book_view_get_backend (EDataBookView *view)
739 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
741 return view->priv->backend;
745 * e_data_book_view_get_sexp:
746 * @view: an #EDataBookView
748 * Gets the s-expression used for matching contacts to @view.
750 * Returns: The #EBookBackendSExp used.
755 e_data_book_view_get_sexp (EDataBookView *view)
757 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
759 return view->priv->sexp;
763 * e_data_book_view_get_connection:
764 * @view: an #EDataBookView
766 * Returns the #GDBusConnection on which the AddressBookView D-Bus
767 * interface is exported.
769 * Returns: the #GDBusConnection
774 e_data_book_view_get_connection (EDataBookView *view)
776 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
778 return view->priv->connection;
782 * e_data_book_view_get_object_path:
783 * @view: an #EDataBookView
785 * Returns the object path at which the AddressBookView D-Bus interface
788 * Returns: the object path
793 e_data_book_view_get_object_path (EDataBookView *view)
795 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
797 return view->priv->object_path;
801 * e_data_book_view_get_flags:
802 * @view: an #EDataBookView
804 * Gets the #EBookClientViewFlags that control the behaviour of @view.
806 * Returns: the flags for @view.
811 e_data_book_view_get_flags (EDataBookView *view)
813 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), 0);
815 return view->priv->flags;
819 * Queue @vcard to be sent as a change notification.
822 notify_change (EDataBookView *view,
826 gchar *utf8_vcard, *utf8_id;
828 send_pending_adds (view);
829 send_pending_removes (view);
831 if (view->priv->changes->len == THRESHOLD_ITEMS * 2) {
832 send_pending_changes (view);
835 if (view->priv->send_uids_only == FALSE) {
836 utf8_vcard = e_util_utf8_make_valid (vcard);
837 g_array_append_val (view->priv->changes, utf8_vcard);
840 utf8_id = e_util_utf8_make_valid (id);
841 g_array_append_val (view->priv->changes, utf8_id);
843 ensure_pending_flush_timeout (view);
847 * Queue @id to be sent as a change notification.
850 notify_remove (EDataBookView *view,
855 send_pending_adds (view);
856 send_pending_changes (view);
858 if (view->priv->removes->len == THRESHOLD_ITEMS) {
859 send_pending_removes (view);
862 valid_id = e_util_utf8_make_valid (id);
863 g_array_append_val (view->priv->removes, valid_id);
864 g_hash_table_remove (view->priv->ids, valid_id);
866 ensure_pending_flush_timeout (view);
870 * Queue @id and @vcard to be sent as a change notification.
873 notify_add (EDataBookView *view,
877 EBookClientViewFlags flags;
878 gchar *utf8_vcard, *utf8_id;
880 send_pending_changes (view);
881 send_pending_removes (view);
883 utf8_id = e_util_utf8_make_valid (id);
885 /* Do not send contact add notifications during initial stage */
886 flags = e_data_book_view_get_flags (view);
887 if (view->priv->complete || (flags & E_BOOK_CLIENT_VIEW_FLAGS_NOTIFY_INITIAL) != 0) {
888 gchar *utf8_id_copy = g_strdup (utf8_id);
890 if (view->priv->adds->len == THRESHOLD_ITEMS) {
891 send_pending_adds (view);
894 if (view->priv->send_uids_only == FALSE) {
895 utf8_vcard = e_util_utf8_make_valid (vcard);
896 g_array_append_val (view->priv->adds, utf8_vcard);
899 g_array_append_val (view->priv->adds, utf8_id_copy);
901 ensure_pending_flush_timeout (view);
904 g_hash_table_insert (view->priv->ids, utf8_id, GUINT_TO_POINTER (1));
908 id_is_in_view (EDataBookView *view,
914 g_return_val_if_fail (view != NULL, FALSE);
915 g_return_val_if_fail (id != NULL, FALSE);
917 valid_id = e_util_utf8_make_valid (id);
918 res = g_hash_table_lookup (view->priv->ids, valid_id) != NULL;
925 * e_data_book_view_notify_update:
926 * @view: an #EDataBookView
927 * @contact: an #EContact
929 * Notify listeners that @contact has changed. This can
930 * trigger an add, change or removal event depending on
931 * whether the change causes the contact to start matching,
932 * no longer match, or stay matching the query specified
936 e_data_book_view_notify_update (EDataBookView *view,
937 const EContact *contact)
939 gboolean currently_in_view, want_in_view;
943 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
944 g_return_if_fail (E_IS_CONTACT (contact));
946 if (!view->priv->running)
949 g_mutex_lock (&view->priv->pending_mutex);
951 id = e_contact_get_const ((EContact *) contact, E_CONTACT_UID);
953 currently_in_view = id_is_in_view (view, id);
954 want_in_view = e_book_backend_sexp_match_contact (
955 view->priv->sexp, (EContact *) contact);
958 vcard = e_vcard_to_string (
960 EVC_FORMAT_VCARD_30);
962 if (currently_in_view)
963 notify_change (view, id, vcard);
965 notify_add (view, id, vcard);
969 if (currently_in_view)
970 notify_remove (view, id);
971 /* else nothing; we're removing a card that wasn't there */
974 g_mutex_unlock (&view->priv->pending_mutex);
978 * e_data_book_view_notify_update_vcard:
979 * @view: an #EDataBookView
980 * @vcard: a plain vCard
982 * Notify listeners that @vcard has changed. This can
983 * trigger an add, change or removal event depending on
984 * whether the change causes the contact to start matching,
985 * no longer match, or stay matching the query specified
986 * by @view. This method should be preferred over
987 * e_data_book_view_notify_update() when the native
988 * representation of a contact is a vCard.
991 e_data_book_view_notify_update_vcard (EDataBookView *view,
995 gboolean currently_in_view, want_in_view;
998 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
999 g_return_if_fail (id != NULL);
1000 g_return_if_fail (vcard != NULL);
1002 if (!view->priv->running)
1005 g_mutex_lock (&view->priv->pending_mutex);
1007 contact = e_contact_new_from_vcard_with_uid (vcard, id);
1008 currently_in_view = id_is_in_view (view, id);
1009 want_in_view = e_book_backend_sexp_match_contact (
1010 view->priv->sexp, contact);
1013 if (currently_in_view)
1014 notify_change (view, id, vcard);
1016 notify_add (view, id, vcard);
1018 if (currently_in_view)
1019 notify_remove (view, id);
1022 /* Do this last so that id is still valid when notify_ is called */
1023 g_object_unref (contact);
1025 g_mutex_unlock (&view->priv->pending_mutex);
1029 * e_data_book_view_notify_update_prefiltered_vcard:
1030 * @view: an #EDataBookView
1031 * @id: the UID of this contact
1032 * @vcard: a plain vCard
1034 * Notify listeners that @vcard has changed. This can
1035 * trigger an add, change or removal event depending on
1036 * whether the change causes the contact to start matching,
1037 * no longer match, or stay matching the query specified
1038 * by @view. This method should be preferred over
1039 * e_data_book_view_notify_update() when the native
1040 * representation of a contact is a vCard.
1042 * The important difference between this method and
1043 * e_data_book_view_notify_update() and
1044 * e_data_book_view_notify_update_vcard() is
1045 * that it doesn't match the contact against the book view query to see if it
1046 * should be included, it assumes that this has been done and the contact is
1047 * known to exist in the view.
1050 e_data_book_view_notify_update_prefiltered_vcard (EDataBookView *view,
1054 gboolean currently_in_view;
1056 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
1057 g_return_if_fail (id != NULL);
1058 g_return_if_fail (vcard != NULL);
1060 if (!view->priv->running)
1063 g_mutex_lock (&view->priv->pending_mutex);
1065 currently_in_view = id_is_in_view (view, id);
1067 if (currently_in_view)
1068 notify_change (view, id, vcard);
1070 notify_add (view, id, vcard);
1072 g_mutex_unlock (&view->priv->pending_mutex);
1076 * e_data_book_view_notify_remove:
1077 * @view: an #EDataBookView
1078 * @id: a unique contact ID
1080 * Notify listeners that a contact specified by @id
1081 * was removed from @view.
1084 e_data_book_view_notify_remove (EDataBookView *view,
1087 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
1088 g_return_if_fail (id != NULL);
1090 if (!view->priv->running)
1093 g_mutex_lock (&view->priv->pending_mutex);
1095 if (id_is_in_view (view, id))
1096 notify_remove (view, id);
1098 g_mutex_unlock (&view->priv->pending_mutex);
1102 * e_data_book_view_notify_complete:
1103 * @view: an #EDataBookView
1104 * @error: the error of the query, if any
1106 * Notifies listeners that all pending updates on @view
1107 * have been sent. The listener's information should now be
1108 * in sync with the backend's.
1111 e_data_book_view_notify_complete (EDataBookView *view,
1112 const GError *error)
1116 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
1118 if (!view->priv->running)
1121 /* View is complete */
1122 view->priv->complete = TRUE;
1124 g_mutex_lock (&view->priv->pending_mutex);
1126 send_pending_adds (view);
1127 send_pending_changes (view);
1128 send_pending_removes (view);
1130 g_mutex_unlock (&view->priv->pending_mutex);
1132 strv_error = e_gdbus_templates_encode_error (error);
1133 e_gdbus_book_view_emit_complete (
1134 view->priv->gdbus_object,
1135 (const gchar * const *) strv_error);
1136 g_strfreev (strv_error);
1140 * e_data_book_view_notify_progress:
1141 * @view: an #EDataBookView
1142 * @percent: percent done; use -1 when not available
1143 * @message: a text message
1145 * Provides listeners with a human-readable text describing the
1146 * current backend operation. This can be used for progress
1152 e_data_book_view_notify_progress (EDataBookView *view,
1154 const gchar *message)
1156 gchar *gdbus_message = NULL;
1158 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
1160 if (!view->priv->running)
1163 e_gdbus_book_view_emit_progress (
1164 view->priv->gdbus_object, percent,
1165 e_util_ensure_gdbus_string (message, &gdbus_message));
1167 g_free (gdbus_message);
1171 * e_data_book_view_get_fields_of_interest:
1172 * @view: an #EDataBookView
1174 * Returns: Hash table of field names which the listener is interested in.
1175 * Backends can return fully populated objects, but the listener advertised
1176 * that it will use only these. Returns %NULL for all available fields.
1178 * Note: The data pointer in the hash table has no special meaning, it's
1179 * only GINT_TO_POINTER(1) for easier checking. Also, field names are
1180 * compared case insensitively.
1183 e_data_book_view_get_fields_of_interest (EDataBookView *view)
1185 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
1187 return view->priv->fields_of_interest;