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;
81 /* Forward Declarations */
82 static void e_data_book_view_initable_init (GInitableIface *interface);
84 G_DEFINE_TYPE_WITH_CODE (
88 G_IMPLEMENT_INTERFACE (
90 e_data_book_view_initable_init))
93 str_ic_hash (gconstpointer key)
96 const gchar *str = key;
102 for (ii = 0; str[ii] != '\0'; ii++)
103 hash = hash * 33 + g_ascii_tolower (str[ii]);
109 str_ic_equal (gconstpointer a,
112 const gchar *stra = a;
113 const gchar *strb = b;
116 if (stra == NULL && strb == NULL)
119 if (stra == NULL || strb == NULL)
122 for (ii = 0; stra[ii] != '\0' && strb[ii] != '\0'; ii++) {
123 if (g_ascii_tolower (stra[ii]) != g_ascii_tolower (strb[ii]))
127 return stra[ii] == strb[ii];
131 reset_array (GArray *array)
136 /* Free stored strings */
137 for (i = 0; i < array->len; i++) {
138 tmp = g_array_index (array, gchar *, i);
142 /* Force the array size to 0 */
143 g_array_set_size (array, 0);
147 send_pending_adds (EDataBookView *view)
149 if (view->priv->adds->len == 0)
152 e_gdbus_book_view_emit_objects_added (
153 view->priv->gdbus_object,
154 (const gchar * const *) view->priv->adds->data);
155 reset_array (view->priv->adds);
159 send_pending_changes (EDataBookView *view)
161 if (view->priv->changes->len == 0)
164 e_gdbus_book_view_emit_objects_modified (
165 view->priv->gdbus_object,
166 (const gchar * const *) view->priv->changes->data);
167 reset_array (view->priv->changes);
171 send_pending_removes (EDataBookView *view)
173 if (view->priv->removes->len == 0)
176 e_gdbus_book_view_emit_objects_removed (
177 view->priv->gdbus_object,
178 (const gchar * const *) view->priv->removes->data);
179 reset_array (view->priv->removes);
183 pending_flush_timeout_cb (gpointer data)
185 EDataBookView *view = data;
187 g_mutex_lock (&view->priv->pending_mutex);
189 view->priv->flush_id = 0;
191 send_pending_adds (view);
192 send_pending_changes (view);
193 send_pending_removes (view);
195 g_mutex_unlock (&view->priv->pending_mutex);
201 ensure_pending_flush_timeout (EDataBookView *view)
203 if (view->priv->flush_id > 0)
206 view->priv->flush_id = g_timeout_add_seconds (
207 THRESHOLD_SECONDS, pending_flush_timeout_cb, view);
211 book_destroyed_cb (gpointer data,
214 EDataBookView *view = E_DATA_BOOK_VIEW (data);
216 /* The book has just died, so unset the pointer so
217 * we don't try and remove a dead weak reference. */
218 view->priv->book = NULL;
220 /* If the view is running stop it here. */
221 if (view->priv->running) {
222 e_book_backend_stop_view (view->priv->backend, view);
223 view->priv->running = FALSE;
224 view->priv->complete = FALSE;
229 bookview_start_thread (gpointer data)
231 EDataBookView *view = data;
233 if (view->priv->running)
234 e_book_backend_start_view (view->priv->backend, view);
235 g_object_unref (view);
241 impl_DataBookView_start (EGdbusBookView *object,
242 GDBusMethodInvocation *invocation,
247 view->priv->running = TRUE;
248 view->priv->complete = FALSE;
250 thread = g_thread_new (
251 NULL, bookview_start_thread, g_object_ref (view));
252 g_thread_unref (thread);
254 e_gdbus_book_view_complete_start (object, invocation, NULL);
260 bookview_stop_thread (gpointer data)
262 EDataBookView *view = data;
264 if (!view->priv->running)
265 e_book_backend_stop_view (view->priv->backend, view);
266 g_object_unref (view);
272 impl_DataBookView_stop (EGdbusBookView *object,
273 GDBusMethodInvocation *invocation,
278 view->priv->running = FALSE;
279 view->priv->complete = FALSE;
281 thread = g_thread_new (
282 NULL, bookview_stop_thread, g_object_ref (view));
283 g_thread_unref (thread);
285 e_gdbus_book_view_complete_stop (object, invocation, NULL);
291 impl_DataBookView_setFlags (EGdbusBookView *object,
292 GDBusMethodInvocation *invocation,
293 EBookClientViewFlags flags,
296 view->priv->flags = flags;
298 e_gdbus_book_view_complete_set_flags (object, invocation, NULL);
304 impl_DataBookView_dispose (EGdbusBookView *object,
305 GDBusMethodInvocation *invocation,
308 e_gdbus_book_view_complete_dispose (object, invocation, NULL);
310 e_book_backend_stop_view (view->priv->backend, view);
311 view->priv->running = FALSE;
312 e_book_backend_remove_view (view->priv->backend, view);
314 g_object_unref (view);
320 impl_DataBookView_set_fields_of_interest (EGdbusBookView *object,
321 GDBusMethodInvocation *invocation,
322 const gchar * const *in_fields_of_interest,
327 g_return_val_if_fail (in_fields_of_interest != NULL, TRUE);
329 if (view->priv->fields_of_interest != NULL) {
330 g_hash_table_destroy (view->priv->fields_of_interest);
331 view->priv->fields_of_interest = NULL;
334 for (ii = 0; in_fields_of_interest[ii]; ii++) {
335 const gchar *field = in_fields_of_interest[ii];
340 if (view->priv->fields_of_interest == NULL)
341 view->priv->fields_of_interest =
342 g_hash_table_new_full (
343 (GHashFunc) str_ic_hash,
344 (GEqualFunc) str_ic_equal,
345 (GDestroyNotify) g_free,
346 (GDestroyNotify) NULL);
348 g_hash_table_insert (
349 view->priv->fields_of_interest,
350 g_strdup (field), GINT_TO_POINTER (1));
353 e_gdbus_book_view_complete_set_fields_of_interest (
354 object, invocation, NULL);
360 data_book_view_set_backend (EDataBookView *view,
361 EBookBackend *backend)
363 g_return_if_fail (E_IS_BOOK_BACKEND (backend));
364 g_return_if_fail (view->priv->backend == NULL);
366 view->priv->backend = g_object_ref (backend);
370 data_book_view_set_connection (EDataBookView *view,
371 GDBusConnection *connection)
373 g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
374 g_return_if_fail (view->priv->connection == NULL);
376 view->priv->connection = g_object_ref (connection);
380 data_book_view_set_object_path (EDataBookView *view,
381 const gchar *object_path)
383 g_return_if_fail (object_path != NULL);
384 g_return_if_fail (view->priv->object_path == NULL);
386 view->priv->object_path = g_strdup (object_path);
390 data_book_view_set_sexp (EDataBookView *view,
391 EBookBackendSExp *sexp)
393 g_return_if_fail (E_IS_BOOK_BACKEND_SEXP (sexp));
394 g_return_if_fail (view->priv->sexp == NULL);
396 view->priv->sexp = g_object_ref (sexp);
400 data_book_view_set_property (GObject *object,
405 switch (property_id) {
407 data_book_view_set_backend (
408 E_DATA_BOOK_VIEW (object),
409 g_value_get_object (value));
412 case PROP_CONNECTION:
413 data_book_view_set_connection (
414 E_DATA_BOOK_VIEW (object),
415 g_value_get_object (value));
418 case PROP_OBJECT_PATH:
419 data_book_view_set_object_path (
420 E_DATA_BOOK_VIEW (object),
421 g_value_get_string (value));
425 data_book_view_set_sexp (
426 E_DATA_BOOK_VIEW (object),
427 g_value_get_object (value));
431 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
435 data_book_view_get_property (GObject *object,
440 switch (property_id) {
444 e_data_book_view_get_backend (
445 E_DATA_BOOK_VIEW (object)));
448 case PROP_CONNECTION:
451 e_data_book_view_get_connection (
452 E_DATA_BOOK_VIEW (object)));
455 case PROP_OBJECT_PATH:
458 e_data_book_view_get_object_path (
459 E_DATA_BOOK_VIEW (object)));
465 e_data_book_view_get_sexp (
466 E_DATA_BOOK_VIEW (object)));
470 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
474 data_book_view_dispose (GObject *object)
476 EDataBookViewPrivate *priv;
478 priv = E_DATA_BOOK_VIEW_GET_PRIVATE (object);
480 if (priv->connection != NULL) {
481 g_object_unref (priv->connection);
482 priv->connection = NULL;
485 if (priv->book != NULL) {
486 /* Remove the weak reference */
487 g_object_weak_unref (
488 G_OBJECT (priv->book),
489 book_destroyed_cb, object);
493 if (priv->backend != NULL) {
494 g_object_unref (priv->backend);
495 priv->backend = NULL;
498 if (priv->sexp != NULL) {
499 g_object_unref (priv->sexp);
503 g_mutex_lock (&priv->pending_mutex);
505 if (priv->flush_id > 0) {
506 g_source_remove (priv->flush_id);
510 g_mutex_unlock (&priv->pending_mutex);
512 /* Chain up to parent's dispose() method. */
513 G_OBJECT_CLASS (e_data_book_view_parent_class)->dispose (object);
517 data_book_view_finalize (GObject *object)
519 EDataBookViewPrivate *priv;
521 priv = E_DATA_BOOK_VIEW_GET_PRIVATE (object);
523 g_free (priv->object_path);
525 reset_array (priv->adds);
526 reset_array (priv->changes);
527 reset_array (priv->removes);
528 g_array_free (priv->adds, TRUE);
529 g_array_free (priv->changes, TRUE);
530 g_array_free (priv->removes, TRUE);
532 if (priv->fields_of_interest)
533 g_hash_table_destroy (priv->fields_of_interest);
535 g_mutex_clear (&priv->pending_mutex);
537 g_hash_table_destroy (priv->ids);
539 /* Chain up to parent's finalize() method. */
540 G_OBJECT_CLASS (e_data_book_view_parent_class)->finalize (object);
544 data_book_view_initable_init (GInitable *initable,
545 GCancellable *cancellable,
550 view = E_DATA_BOOK_VIEW (initable);
552 return e_gdbus_book_view_register_object (
553 view->priv->gdbus_object,
554 view->priv->connection,
555 view->priv->object_path,
560 e_data_book_view_class_init (EDataBookViewClass *class)
562 GObjectClass *object_class;
564 g_type_class_add_private (class, sizeof (EDataBookViewPrivate));
566 object_class = G_OBJECT_CLASS (class);
567 object_class->set_property = data_book_view_set_property;
568 object_class->get_property = data_book_view_get_property;
569 object_class->dispose = data_book_view_dispose;
570 object_class->finalize = data_book_view_finalize;
572 g_object_class_install_property (
575 g_param_spec_object (
578 "The backend being monitored",
581 G_PARAM_CONSTRUCT_ONLY |
582 G_PARAM_STATIC_STRINGS));
584 g_object_class_install_property (
587 g_param_spec_object (
590 "The GDBusConnection on which "
591 "to export the view interface",
592 G_TYPE_DBUS_CONNECTION,
594 G_PARAM_CONSTRUCT_ONLY |
595 G_PARAM_STATIC_STRINGS));
597 g_object_class_install_property (
600 g_param_spec_string (
603 "The object path at which to "
604 "export the view interface",
607 G_PARAM_CONSTRUCT_ONLY |
608 G_PARAM_STATIC_STRINGS));
610 g_object_class_install_property (
613 g_param_spec_object (
616 "The query expression for this view",
617 E_TYPE_BOOK_BACKEND_SEXP,
619 G_PARAM_CONSTRUCT_ONLY |
620 G_PARAM_STATIC_STRINGS));
624 e_data_book_view_initable_init (GInitableIface *interface)
626 interface->init = data_book_view_initable_init;
630 e_data_book_view_init (EDataBookView *view)
632 view->priv = E_DATA_BOOK_VIEW_GET_PRIVATE (view);
634 view->priv->flags = E_BOOK_CLIENT_VIEW_FLAGS_NOTIFY_INITIAL;
636 view->priv->gdbus_object = e_gdbus_book_view_stub_new ();
638 view->priv->gdbus_object, "handle-start",
639 G_CALLBACK (impl_DataBookView_start), view);
641 view->priv->gdbus_object, "handle-stop",
642 G_CALLBACK (impl_DataBookView_stop), view);
644 view->priv->gdbus_object, "handle-set-flags",
645 G_CALLBACK (impl_DataBookView_setFlags), view);
647 view->priv->gdbus_object, "handle-dispose",
648 G_CALLBACK (impl_DataBookView_dispose), view);
650 view->priv->gdbus_object, "handle-set-fields-of-interest",
651 G_CALLBACK (impl_DataBookView_set_fields_of_interest), view);
653 view->priv->fields_of_interest = NULL;
654 view->priv->running = FALSE;
655 view->priv->complete = FALSE;
656 g_mutex_init (&view->priv->pending_mutex);
658 /* THRESHOLD_ITEMS * 2 because we store UID and vcard */
659 view->priv->adds = g_array_sized_new (
660 TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS * 2);
661 view->priv->changes = g_array_sized_new (
662 TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS * 2);
663 view->priv->removes = g_array_sized_new (
664 TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS);
666 view->priv->ids = g_hash_table_new_full (
667 (GHashFunc) g_str_hash,
668 (GEqualFunc) g_str_equal,
669 (GDestroyNotify) g_free,
670 (GDestroyNotify) NULL);
672 view->priv->flush_id = 0;
676 * e_data_book_view_new:
677 * @book: The #EDataBook to search
678 * @sexp: The query as an #EBookBackendSExp
680 * Create a new #EDataBookView for the given #EBook, filtering on @sexp,
681 * and place it on DBus at the object path #path.
684 e_data_book_view_new (EDataBook *book,
685 EBookBackendSExp *sexp,
686 GDBusConnection *connection,
687 const gchar *object_path,
691 EBookBackend *backend;
693 g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
694 g_return_val_if_fail (E_IS_BOOK_BACKEND_SEXP (sexp), NULL);
695 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
696 g_return_val_if_fail (object_path != NULL, NULL);
698 backend = e_data_book_get_backend (book);
700 view = g_initable_new (
701 E_TYPE_DATA_BOOK_VIEW, NULL, error,
703 "connection", connection,
704 "object-path", object_path,
710 view->priv->book = book;
711 /* Attach a weak reference to the book, so
712 * if it dies the book view is destroyed too. */
714 G_OBJECT (view->priv->book),
715 book_destroyed_cb, view);
721 * e_data_book_view_get_backend:
722 * @view: an #EDataBookView
724 * Gets the backend that @view is querying.
726 * Returns: The associated #EBookBackend.
729 e_data_book_view_get_backend (EDataBookView *view)
731 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
733 return view->priv->backend;
737 * e_data_book_view_get_sexp:
738 * @view: an #EDataBookView
740 * Gets the s-expression used for matching contacts to @view.
742 * Returns: The #EBookBackendSExp used.
747 e_data_book_view_get_sexp (EDataBookView *view)
749 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
751 return view->priv->sexp;
755 * e_data_book_view_get_connection:
756 * @view: an #EDataBookView
758 * Returns the #GDBusConnection on which the AddressBookView D-Bus
759 * interface is exported.
761 * Returns: the #GDBusConnection
766 e_data_book_view_get_connection (EDataBookView *view)
768 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
770 return view->priv->connection;
774 * e_data_book_view_get_object_path:
775 * @view: an #EDataBookView
777 * Returns the object path at which the AddressBookView D-Bus interface
780 * Returns: the object path
785 e_data_book_view_get_object_path (EDataBookView *view)
787 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
789 return view->priv->object_path;
793 * e_data_book_view_get_flags:
794 * @view: an #EDataBookView
796 * Gets the #EBookClientViewFlags that control the behaviour of @view.
798 * Returns: the flags for @view.
803 e_data_book_view_get_flags (EDataBookView *view)
805 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), 0);
807 return view->priv->flags;
811 * Queue @vcard to be sent as a change notification.
814 notify_change (EDataBookView *view,
818 gchar *utf8_vcard, *utf8_id;
820 send_pending_adds (view);
821 send_pending_removes (view);
823 if (view->priv->changes->len == THRESHOLD_ITEMS * 2) {
824 send_pending_changes (view);
827 utf8_vcard = e_util_utf8_make_valid (vcard);
828 utf8_id = e_util_utf8_make_valid (id);
830 g_array_append_val (view->priv->changes, utf8_vcard);
831 g_array_append_val (view->priv->changes, utf8_id);
833 ensure_pending_flush_timeout (view);
837 * Queue @id to be sent as a change notification.
840 notify_remove (EDataBookView *view,
845 send_pending_adds (view);
846 send_pending_changes (view);
848 if (view->priv->removes->len == THRESHOLD_ITEMS) {
849 send_pending_removes (view);
852 valid_id = e_util_utf8_make_valid (id);
853 g_array_append_val (view->priv->removes, valid_id);
854 g_hash_table_remove (view->priv->ids, valid_id);
856 ensure_pending_flush_timeout (view);
860 * Queue @id and @vcard to be sent as a change notification.
863 notify_add (EDataBookView *view,
867 EBookClientViewFlags flags;
868 gchar *utf8_vcard, *utf8_id;
870 send_pending_changes (view);
871 send_pending_removes (view);
873 utf8_id = e_util_utf8_make_valid (id);
875 /* Do not send contact add notifications during initial stage */
876 flags = e_data_book_view_get_flags (view);
877 if (view->priv->complete || (flags & E_BOOK_CLIENT_VIEW_FLAGS_NOTIFY_INITIAL) != 0) {
878 gchar *utf8_id_copy = g_strdup (utf8_id);
880 if (view->priv->adds->len == THRESHOLD_ITEMS) {
881 send_pending_adds (view);
884 utf8_vcard = e_util_utf8_make_valid (vcard);
886 g_array_append_val (view->priv->adds, utf8_vcard);
887 g_array_append_val (view->priv->adds, utf8_id_copy);
889 ensure_pending_flush_timeout (view);
892 g_hash_table_insert (view->priv->ids, utf8_id, GUINT_TO_POINTER (1));
896 id_is_in_view (EDataBookView *view,
902 g_return_val_if_fail (view != NULL, FALSE);
903 g_return_val_if_fail (id != NULL, FALSE);
905 valid_id = e_util_utf8_make_valid (id);
906 res = g_hash_table_lookup (view->priv->ids, valid_id) != NULL;
913 * e_data_book_view_notify_update:
914 * @view: an #EDataBookView
915 * @contact: an #EContact
917 * Notify listeners that @contact has changed. This can
918 * trigger an add, change or removal event depending on
919 * whether the change causes the contact to start matching,
920 * no longer match, or stay matching the query specified
924 e_data_book_view_notify_update (EDataBookView *view,
925 const EContact *contact)
927 gboolean currently_in_view, want_in_view;
931 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
932 g_return_if_fail (E_IS_CONTACT (contact));
934 if (!view->priv->running)
937 g_mutex_lock (&view->priv->pending_mutex);
939 id = e_contact_get_const ((EContact *) contact, E_CONTACT_UID);
941 currently_in_view = id_is_in_view (view, id);
942 want_in_view = e_book_backend_sexp_match_contact (
943 view->priv->sexp, (EContact *) contact);
946 vcard = e_vcard_to_string (
948 EVC_FORMAT_VCARD_30);
950 if (currently_in_view)
951 notify_change (view, id, vcard);
953 notify_add (view, id, vcard);
957 if (currently_in_view)
958 notify_remove (view, id);
959 /* else nothing; we're removing a card that wasn't there */
962 g_mutex_unlock (&view->priv->pending_mutex);
966 * e_data_book_view_notify_update_vcard:
967 * @view: an #EDataBookView
968 * @vcard: a plain vCard
970 * Notify listeners that @vcard has changed. This can
971 * trigger an add, change or removal event depending on
972 * whether the change causes the contact to start matching,
973 * no longer match, or stay matching the query specified
974 * by @view. This method should be preferred over
975 * e_data_book_view_notify_update() when the native
976 * representation of a contact is a vCard.
979 e_data_book_view_notify_update_vcard (EDataBookView *view,
983 gboolean currently_in_view, want_in_view;
986 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
987 g_return_if_fail (id != NULL);
988 g_return_if_fail (vcard != NULL);
990 if (!view->priv->running)
993 g_mutex_lock (&view->priv->pending_mutex);
995 contact = e_contact_new_from_vcard_with_uid (vcard, id);
996 currently_in_view = id_is_in_view (view, id);
997 want_in_view = e_book_backend_sexp_match_contact (
998 view->priv->sexp, contact);
1001 if (currently_in_view)
1002 notify_change (view, id, vcard);
1004 notify_add (view, id, vcard);
1006 if (currently_in_view)
1007 notify_remove (view, id);
1010 /* Do this last so that id is still valid when notify_ is called */
1011 g_object_unref (contact);
1013 g_mutex_unlock (&view->priv->pending_mutex);
1017 * e_data_book_view_notify_update_prefiltered_vcard:
1018 * @view: an #EDataBookView
1019 * @id: the UID of this contact
1020 * @vcard: a plain vCard
1022 * Notify listeners that @vcard has changed. This can
1023 * trigger an add, change or removal event depending on
1024 * whether the change causes the contact to start matching,
1025 * no longer match, or stay matching the query specified
1026 * by @view. This method should be preferred over
1027 * e_data_book_view_notify_update() when the native
1028 * representation of a contact is a vCard.
1030 * The important difference between this method and
1031 * e_data_book_view_notify_update() and
1032 * e_data_book_view_notify_update_vcard() is
1033 * that it doesn't match the contact against the book view query to see if it
1034 * should be included, it assumes that this has been done and the contact is
1035 * known to exist in the view.
1038 e_data_book_view_notify_update_prefiltered_vcard (EDataBookView *view,
1042 gboolean currently_in_view;
1044 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
1045 g_return_if_fail (id != NULL);
1046 g_return_if_fail (vcard != NULL);
1048 if (!view->priv->running)
1051 g_mutex_lock (&view->priv->pending_mutex);
1053 currently_in_view = id_is_in_view (view, id);
1055 if (currently_in_view)
1056 notify_change (view, id, vcard);
1058 notify_add (view, id, vcard);
1060 g_mutex_unlock (&view->priv->pending_mutex);
1064 * e_data_book_view_notify_remove:
1065 * @view: an #EDataBookView
1066 * @id: a unique contact ID
1068 * Notify listeners that a contact specified by @id
1069 * was removed from @view.
1072 e_data_book_view_notify_remove (EDataBookView *view,
1075 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
1076 g_return_if_fail (id != NULL);
1078 if (!view->priv->running)
1081 g_mutex_lock (&view->priv->pending_mutex);
1083 if (id_is_in_view (view, id))
1084 notify_remove (view, id);
1086 g_mutex_unlock (&view->priv->pending_mutex);
1090 * e_data_book_view_notify_complete:
1091 * @view: an #EDataBookView
1092 * @error: the error of the query, if any
1094 * Notifies listeners that all pending updates on @view
1095 * have been sent. The listener's information should now be
1096 * in sync with the backend's.
1099 e_data_book_view_notify_complete (EDataBookView *view,
1100 const GError *error)
1104 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
1106 if (!view->priv->running)
1109 /* View is complete */
1110 view->priv->complete = TRUE;
1112 g_mutex_lock (&view->priv->pending_mutex);
1114 send_pending_adds (view);
1115 send_pending_changes (view);
1116 send_pending_removes (view);
1118 g_mutex_unlock (&view->priv->pending_mutex);
1120 strv_error = e_gdbus_templates_encode_error (error);
1121 e_gdbus_book_view_emit_complete (
1122 view->priv->gdbus_object,
1123 (const gchar * const *) strv_error);
1124 g_strfreev (strv_error);
1128 * e_data_book_view_notify_progress:
1129 * @view: an #EDataBookView
1130 * @percent: percent done; use -1 when not available
1131 * @message: a text message
1133 * Provides listeners with a human-readable text describing the
1134 * current backend operation. This can be used for progress
1140 e_data_book_view_notify_progress (EDataBookView *view,
1142 const gchar *message)
1144 gchar *gdbus_message = NULL;
1146 g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
1148 if (!view->priv->running)
1151 e_gdbus_book_view_emit_progress (
1152 view->priv->gdbus_object, percent,
1153 e_util_ensure_gdbus_string (message, &gdbus_message));
1155 g_free (gdbus_message);
1159 * e_data_book_view_get_fields_of_interest:
1160 * @view: an #EDataBookView
1162 * Returns: Hash table of field names which the listener is interested in.
1163 * Backends can return fully populated objects, but the listener advertised
1164 * that it will use only these. Returns %NULL for all available fields.
1166 * Note: The data pointer in the hash table has no special meaning, it's
1167 * only GINT_TO_POINTER(1) for easier checking. Also, field names are
1168 * compared case insensitively.
1171 e_data_book_view_get_fields_of_interest (EDataBookView *view)
1173 g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
1175 return view->priv->fields_of_interest;