(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_DATA_BOOK_VIEW, EDataBookViewPrivate))
-static void reset_array (GArray *array);
-static void ensure_pending_flush_timeout (EDataBookView *view);
+/* how many items can be hold in a cache, before propagated to UI */
+#define THRESHOLD_ITEMS 32
-G_DEFINE_TYPE (EDataBookView, e_data_book_view, G_TYPE_OBJECT);
-#define THRESHOLD_ITEMS 32 /* how many items can be hold in a cache, before propagated to UI */
-#define THRESHOLD_SECONDS 2 /* how long to wait until notifications are propagated to UI; in seconds */
+/* how long to wait until notifications are propagated to UI; in seconds */
+#define THRESHOLD_SECONDS 2
struct _EDataBookViewPrivate {
EGdbusBookView *gdbus_object;
EDataBook *book;
EBookBackend *backend;
- gchar * card_query;
- EBookBackendSExp *card_sexp;
+ EBookBackendSExp *sexp;
EBookClientViewFlags flags;
gboolean running;
GHashTable *fields_of_interest;
};
-static void e_data_book_view_dispose (GObject *object);
-static void e_data_book_view_finalize (GObject *object);
-
-static void
-e_data_book_view_class_init (EDataBookViewClass *class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (class);
-
- g_type_class_add_private (class, sizeof (EDataBookViewPrivate));
+G_DEFINE_TYPE (EDataBookView, e_data_book_view, G_TYPE_OBJECT);
- object_class->dispose = e_data_book_view_dispose;
- object_class->finalize = e_data_book_view_finalize;
-}
+enum {
+ PROP_0,
+ PROP_BACKEND,
+ PROP_SEXP
+};
static guint
str_ic_hash (gconstpointer key)
const gchar *str = key;
gint ii;
- if (!str)
+ if (str == NULL)
return hash;
- for (ii = 0; str[ii]; ii++) {
+ for (ii = 0; str[ii] != '\0'; ii++)
hash = hash * 33 + g_ascii_tolower (str[ii]);
- }
return hash;
}
str_ic_equal (gconstpointer a,
gconstpointer b)
{
- const gchar *stra = a, *strb = b;
+ const gchar *stra = a;
+ const gchar *strb = b;
gint ii;
- if (!stra && !strb)
+ if (stra == NULL && strb == NULL)
return TRUE;
- if (!stra || !strb)
+ if (stra == NULL || strb == NULL)
return FALSE;
- for (ii = 0; stra[ii] && strb[ii]; ii++) {
+ for (ii = 0; stra[ii] != '\0' && strb[ii] != '\0'; ii++) {
if (g_ascii_tolower (stra[ii]) != g_ascii_tolower (strb[ii]))
return FALSE;
}
return stra[ii] == strb[ii];
}
-/**
- * e_data_book_view_register_gdbus_object:
- *
- * Since: 2.32
- **/
-guint
-e_data_book_view_register_gdbus_object (EDataBookView *query,
- GDBusConnection *connection,
- const gchar *object_path,
- GError **error)
-{
- g_return_val_if_fail (query != NULL, 0);
- g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (query), 0);
- g_return_val_if_fail (connection != NULL, 0);
- g_return_val_if_fail (object_path != NULL, 0);
-
- return e_gdbus_book_view_register_object (query->priv->gdbus_object, connection, object_path, error);
-}
-
static void
-book_destroyed_cb (gpointer data,
- GObject *dead)
+reset_array (GArray *array)
{
- EDataBookView *view = E_DATA_BOOK_VIEW (data);
- EDataBookViewPrivate *priv = view->priv;
-
- /* The book has just died, so unset the pointer so we don't try and remove a
- * dead weak reference. */
- view->priv->book = NULL;
+ gint i = 0;
+ gchar *tmp = NULL;
- /* If the view is running stop it here. */
- if (priv->running) {
- e_book_backend_stop_view (priv->backend, view);
- priv->running = FALSE;
- priv->complete = FALSE;
+ /* Free stored strings */
+ for (i = 0; i < array->len; i++) {
+ tmp = g_array_index (array, gchar *, i);
+ g_free (tmp);
}
+
+ /* Force the array size to 0 */
+ g_array_set_size (array, 0);
}
static void
send_pending_adds (EDataBookView *view)
{
- EDataBookViewPrivate *priv = view->priv;
-
- if (priv->adds->len == 0)
+ if (view->priv->adds->len == 0)
return;
- e_gdbus_book_view_emit_objects_added (view->priv->gdbus_object, (const gchar * const *) priv->adds->data);
- reset_array (priv->adds);
+ e_gdbus_book_view_emit_objects_added (
+ view->priv->gdbus_object,
+ (const gchar * const *) view->priv->adds->data);
+ reset_array (view->priv->adds);
}
static void
send_pending_changes (EDataBookView *view)
{
- EDataBookViewPrivate *priv = view->priv;
-
- if (priv->changes->len == 0)
+ if (view->priv->changes->len == 0)
return;
- e_gdbus_book_view_emit_objects_modified (view->priv->gdbus_object, (const gchar * const *) priv->changes->data);
- reset_array (priv->changes);
+ e_gdbus_book_view_emit_objects_modified (
+ view->priv->gdbus_object,
+ (const gchar * const *) view->priv->changes->data);
+ reset_array (view->priv->changes);
}
static void
send_pending_removes (EDataBookView *view)
{
- EDataBookViewPrivate *priv = view->priv;
-
- if (priv->removes->len == 0)
+ if (view->priv->removes->len == 0)
return;
- e_gdbus_book_view_emit_objects_removed (view->priv->gdbus_object, (const gchar * const *) priv->removes->data);
- reset_array (priv->removes);
+ e_gdbus_book_view_emit_objects_removed (
+ view->priv->gdbus_object,
+ (const gchar * const *) view->priv->removes->data);
+ reset_array (view->priv->removes);
}
static gboolean
pending_flush_timeout_cb (gpointer data)
{
EDataBookView *view = data;
- EDataBookViewPrivate *priv = view->priv;
- g_mutex_lock (priv->pending_mutex);
+ g_mutex_lock (view->priv->pending_mutex);
- priv->flush_id = 0;
+ view->priv->flush_id = 0;
send_pending_adds (view);
send_pending_changes (view);
send_pending_removes (view);
- g_mutex_unlock (priv->pending_mutex);
+ g_mutex_unlock (view->priv->pending_mutex);
return FALSE;
}
static void
ensure_pending_flush_timeout (EDataBookView *view)
{
- EDataBookViewPrivate *priv = view->priv;
-
- if (priv->flush_id)
- return;
+ if (view->priv->flush_id > 0)
+ return;
+
+ view->priv->flush_id = g_timeout_add_seconds (
+ THRESHOLD_SECONDS, pending_flush_timeout_cb, view);
+}
+
+static void
+book_destroyed_cb (gpointer data,
+ GObject *dead)
+{
+ EDataBookView *view = E_DATA_BOOK_VIEW (data);
+
+ /* The book has just died, so unset the pointer so
+ * we don't try and remove a dead weak reference. */
+ view->priv->book = NULL;
+
+ /* If the view is running stop it here. */
+ if (view->priv->running) {
+ e_book_backend_stop_view (view->priv->backend, view);
+ view->priv->running = FALSE;
+ view->priv->complete = FALSE;
+ }
+}
+
+static gpointer
+bookview_start_thread (gpointer data)
+{
+ EDataBookView *view = data;
+
+ if (view->priv->running)
+ e_book_backend_start_view (view->priv->backend, view);
+ g_object_unref (view);
+
+ return NULL;
+}
+
+static gboolean
+impl_DataBookView_start (EGdbusBookView *object,
+ GDBusMethodInvocation *invocation,
+ EDataBookView *view)
+{
+ GThread *thread;
+
+ view->priv->running = TRUE;
+ view->priv->complete = FALSE;
+
+ thread = g_thread_new (
+ NULL, bookview_start_thread, g_object_ref (view));
+ g_thread_unref (thread);
+
+ e_gdbus_book_view_complete_start (object, invocation, NULL);
+
+ return TRUE;
+}
+
+static gpointer
+bookview_stop_thread (gpointer data)
+{
+ EDataBookView *view = data;
+
+ if (!view->priv->running)
+ e_book_backend_stop_view (view->priv->backend, view);
+ g_object_unref (view);
+
+ return NULL;
+}
+
+static gboolean
+impl_DataBookView_stop (EGdbusBookView *object,
+ GDBusMethodInvocation *invocation,
+ EDataBookView *view)
+{
+ GThread *thread;
+
+ view->priv->running = FALSE;
+ view->priv->complete = FALSE;
+
+ thread = g_thread_new (
+ NULL, bookview_stop_thread, g_object_ref (view));
+ g_thread_unref (thread);
+
+ e_gdbus_book_view_complete_stop (object, invocation, NULL);
+
+ return TRUE;
+}
+
+static gboolean
+impl_DataBookView_setFlags (EGdbusBookView *object,
+ GDBusMethodInvocation *invocation,
+ EBookClientViewFlags flags,
+ EDataBookView *view)
+{
+ view->priv->flags = flags;
+
+ e_gdbus_book_view_complete_set_flags (object, invocation, NULL);
+
+ return TRUE;
+}
+
+static gboolean
+impl_DataBookView_dispose (EGdbusBookView *object,
+ GDBusMethodInvocation *invocation,
+ EDataBookView *view)
+{
+ e_gdbus_book_view_complete_dispose (object, invocation, NULL);
+
+ e_book_backend_stop_view (view->priv->backend, view);
+ view->priv->running = FALSE;
+ e_book_backend_remove_view (view->priv->backend, view);
+
+ g_object_unref (view);
+
+ return TRUE;
+}
+
+static gboolean
+impl_DataBookView_set_fields_of_interest (EGdbusBookView *object,
+ GDBusMethodInvocation *invocation,
+ const gchar * const *in_fields_of_interest,
+ EDataBookView *view)
+{
+ gint ii;
+
+ g_return_val_if_fail (in_fields_of_interest != NULL, TRUE);
+
+ if (view->priv->fields_of_interest != NULL) {
+ g_hash_table_destroy (view->priv->fields_of_interest);
+ view->priv->fields_of_interest = NULL;
+ }
+
+ for (ii = 0; in_fields_of_interest[ii]; ii++) {
+ const gchar *field = in_fields_of_interest[ii];
+
+ if (!*field)
+ continue;
+
+ if (view->priv->fields_of_interest == NULL)
+ view->priv->fields_of_interest =
+ g_hash_table_new_full (
+ (GHashFunc) str_ic_hash,
+ (GEqualFunc) str_ic_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) NULL);
+
+ g_hash_table_insert (
+ view->priv->fields_of_interest,
+ g_strdup (field), GINT_TO_POINTER (1));
+ }
+
+ e_gdbus_book_view_complete_set_fields_of_interest (
+ object, invocation, NULL);
+
+ return TRUE;
+}
+
+static void
+data_book_view_set_backend (EDataBookView *view,
+ EBookBackend *backend)
+{
+ g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+ g_return_if_fail (view->priv->backend == NULL);
+
+ view->priv->backend = g_object_ref (backend);
+}
+
+static void
+data_book_view_set_sexp (EDataBookView *view,
+ EBookBackendSExp *sexp)
+{
+ g_return_if_fail (E_IS_BOOK_BACKEND_SEXP (sexp));
+ g_return_if_fail (view->priv->sexp == NULL);
+
+ view->priv->sexp = g_object_ref (sexp);
+}
+
+static void
+data_book_view_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BACKEND:
+ data_book_view_set_backend (
+ E_DATA_BOOK_VIEW (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SEXP:
+ data_book_view_set_sexp (
+ E_DATA_BOOK_VIEW (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+data_book_view_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_BACKEND:
+ g_value_set_object (
+ value,
+ e_data_book_view_get_backend (
+ E_DATA_BOOK_VIEW (object)));
+ return;
+
+ case PROP_SEXP:
+ g_value_set_object (
+ value,
+ e_data_book_view_get_sexp (
+ E_DATA_BOOK_VIEW (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+data_book_view_dispose (GObject *object)
+{
+ EDataBookViewPrivate *priv;
+
+ priv = E_DATA_BOOK_VIEW_GET_PRIVATE (object);
+
+ if (priv->book != NULL) {
+ /* Remove the weak reference */
+ g_object_weak_unref (
+ G_OBJECT (priv->book),
+ book_destroyed_cb, object);
+ priv->book = NULL;
+ }
+
+ if (priv->backend != NULL) {
+ g_object_unref (priv->backend);
+ priv->backend = NULL;
+ }
+
+ if (priv->sexp != NULL) {
+ g_object_unref (priv->sexp);
+ priv->sexp = NULL;
+ }
+
+ g_mutex_lock (priv->pending_mutex);
+
+ if (priv->flush_id > 0) {
+ g_source_remove (priv->flush_id);
+ priv->flush_id = 0;
+ }
+
+ g_mutex_unlock (priv->pending_mutex);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_data_book_view_parent_class)->dispose (object);
+}
+
+static void
+data_book_view_finalize (GObject *object)
+{
+ EDataBookViewPrivate *priv;
+
+ priv = E_DATA_BOOK_VIEW_GET_PRIVATE (object);
+
+ reset_array (priv->adds);
+ reset_array (priv->changes);
+ reset_array (priv->removes);
+ g_array_free (priv->adds, TRUE);
+ g_array_free (priv->changes, TRUE);
+ g_array_free (priv->removes, TRUE);
+
+ if (priv->fields_of_interest)
+ g_hash_table_destroy (priv->fields_of_interest);
+
+ g_mutex_free (priv->pending_mutex);
+
+ g_hash_table_destroy (priv->ids);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_data_book_view_parent_class)->finalize (object);
+}
+
+static void
+e_data_book_view_class_init (EDataBookViewClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EDataBookViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = data_book_view_set_property;
+ object_class->get_property = data_book_view_get_property;
+ object_class->dispose = data_book_view_dispose;
+ object_class->finalize = data_book_view_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_BACKEND,
+ g_param_spec_object (
+ "backend",
+ "Backend",
+ "The backend being monitored",
+ E_TYPE_BOOK_BACKEND,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SEXP,
+ g_param_spec_object (
+ "sexp",
+ "S-Expression",
+ "The query expression for this view",
+ E_TYPE_BOOK_BACKEND_SEXP,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_data_book_view_init (EDataBookView *view)
+{
+ view->priv = E_DATA_BOOK_VIEW_GET_PRIVATE (view);
+
+ view->priv->flags = E_BOOK_CLIENT_VIEW_FLAGS_NOTIFY_INITIAL;
+
+ view->priv->gdbus_object = e_gdbus_book_view_stub_new ();
+ g_signal_connect (
+ view->priv->gdbus_object, "handle-start",
+ G_CALLBACK (impl_DataBookView_start), view);
+ g_signal_connect (
+ view->priv->gdbus_object, "handle-stop",
+ G_CALLBACK (impl_DataBookView_stop), view);
+ g_signal_connect (
+ view->priv->gdbus_object, "handle-set-flags",
+ G_CALLBACK (impl_DataBookView_setFlags), view);
+ g_signal_connect (
+ view->priv->gdbus_object, "handle-dispose",
+ G_CALLBACK (impl_DataBookView_dispose), view);
+ g_signal_connect (
+ view->priv->gdbus_object, "handle-set-fields-of-interest",
+ G_CALLBACK (impl_DataBookView_set_fields_of_interest), view);
+
+ view->priv->fields_of_interest = NULL;
+ view->priv->running = FALSE;
+ view->priv->complete = FALSE;
+ view->priv->pending_mutex = g_mutex_new ();
+
+ /* THRESHOLD_ITEMS * 2 because we store UID and vcard */
+ view->priv->adds = g_array_sized_new (
+ TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS * 2);
+ view->priv->changes = g_array_sized_new (
+ TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS * 2);
+ view->priv->removes = g_array_sized_new (
+ TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS);
+
+ view->priv->ids = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) NULL);
+
+ view->priv->flush_id = 0;
+}
+
+/**
+ * e_data_book_view_new:
+ * @book: The #EDataBook to search
+ * @sexp: The query as an #EBookBackendSExp
+ *
+ * Create a new #EDataBookView for the given #EBook, filtering on @sexp,
+ * and place it on DBus at the object path #path.
+ */
+EDataBookView *
+e_data_book_view_new (EDataBook *book,
+ EBookBackendSExp *sexp)
+{
+ EDataBookView *view;
+ EBookBackend *backend;
+
+ g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_SEXP (sexp), NULL);
+
+ backend = e_data_book_get_backend (book);
+
+ view = g_object_new (
+ E_TYPE_DATA_BOOK_VIEW,
+ "backend", backend,
+ "sexp", sexp, NULL);
+
+ view->priv->book = book;
+ /* Attach a weak reference to the book, so
+ * if it dies the book view is destroyed too. */
+ g_object_weak_ref (
+ G_OBJECT (view->priv->book),
+ book_destroyed_cb, view);
+
+ return view;
+}
+
+/**
+ * e_data_book_view_register_gdbus_object:
+ *
+ * Since: 2.32
+ **/
+guint
+e_data_book_view_register_gdbus_object (EDataBookView *query,
+ GDBusConnection *connection,
+ const gchar *object_path,
+ GError **error)
+{
+ g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (query), 0);
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
+ g_return_val_if_fail (object_path != NULL, 0);
+
+ return e_gdbus_book_view_register_object (
+ query->priv->gdbus_object, connection, object_path, error);
+}
+
+/**
+ * e_data_book_view_get_backend:
+ * @view: an #EDataBookView
+ *
+ * Gets the backend that @view is querying.
+ *
+ * Returns: The associated #EBookBackend.
+ **/
+EBookBackend *
+e_data_book_view_get_backend (EDataBookView *view)
+{
+ g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
+
+ return view->priv->backend;
+}
+
+/**
+ * e_data_book_view_get_sexp:
+ * @view: an #EDataBookView
+ *
+ * Gets the s-expression used for matching contacts to @view.
+ *
+ * Returns: The #EBookBackendSExp used.
+ **/
+EBookBackendSExp *
+e_data_book_view_get_sexp (EDataBookView *view)
+{
+ g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
+
+ return view->priv->sexp;
+}
+
+/**
+ * e_data_book_view_get_flags:
+ * @view: an #EDataBookView
+ *
+ * Gets the #EBookClientViewFlags that control the behaviour of @view.
+ *
+ * Returns: the flags for @view.
+ *
+ * Since: 3.4
+ **/
+EBookClientViewFlags
+e_data_book_view_get_flags (EDataBookView *view)
+{
+ g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), 0);
- priv->flush_id = g_timeout_add_seconds (THRESHOLD_SECONDS, pending_flush_timeout_cb, view);
+ return view->priv->flags;
}
/*
const gchar *id,
const gchar *vcard)
{
- EDataBookViewPrivate *priv = view->priv;
gchar *utf8_vcard, *utf8_id;
send_pending_adds (view);
send_pending_removes (view);
- if (priv->changes->len == THRESHOLD_ITEMS * 2) {
+ if (view->priv->changes->len == THRESHOLD_ITEMS * 2) {
send_pending_changes (view);
}
utf8_vcard = e_util_utf8_make_valid (vcard);
utf8_id = e_util_utf8_make_valid (id);
- g_array_append_val (priv->changes, utf8_vcard);
- g_array_append_val (priv->changes, utf8_id);
+ g_array_append_val (view->priv->changes, utf8_vcard);
+ g_array_append_val (view->priv->changes, utf8_id);
ensure_pending_flush_timeout (view);
}
notify_remove (EDataBookView *view,
const gchar *id)
{
- EDataBookViewPrivate *priv = view->priv;
gchar *valid_id;
send_pending_adds (view);
send_pending_changes (view);
- if (priv->removes->len == THRESHOLD_ITEMS) {
+ if (view->priv->removes->len == THRESHOLD_ITEMS) {
send_pending_removes (view);
}
valid_id = e_util_utf8_make_valid (id);
- g_array_append_val (priv->removes, valid_id);
- g_hash_table_remove (priv->ids, valid_id);
+ g_array_append_val (view->priv->removes, valid_id);
+ g_hash_table_remove (view->priv->ids, valid_id);
ensure_pending_flush_timeout (view);
}
const gchar *vcard)
{
EBookClientViewFlags flags;
- EDataBookViewPrivate *priv = view->priv;
gchar *utf8_vcard, *utf8_id;
send_pending_changes (view);
/* Do not send contact add notifications during initial stage */
flags = e_data_book_view_get_flags (view);
- if (priv->complete || (flags & E_BOOK_CLIENT_VIEW_FLAGS_NOTIFY_INITIAL) != 0) {
+ if (view->priv->complete || (flags & E_BOOK_CLIENT_VIEW_FLAGS_NOTIFY_INITIAL) != 0) {
gchar *utf8_id_copy = g_strdup (utf8_id);
- if (priv->adds->len == THRESHOLD_ITEMS) {
+ if (view->priv->adds->len == THRESHOLD_ITEMS) {
send_pending_adds (view);
}
utf8_vcard = e_util_utf8_make_valid (vcard);
- g_array_append_val (priv->adds, utf8_vcard);
- g_array_append_val (priv->adds, utf8_id_copy);
+ g_array_append_val (view->priv->adds, utf8_vcard);
+ g_array_append_val (view->priv->adds, utf8_id_copy);
ensure_pending_flush_timeout (view);
}
- g_hash_table_insert (priv->ids, utf8_id,
- GUINT_TO_POINTER (1));
-}
-
-static gboolean
-impl_DataBookView_set_fields_of_interest (EGdbusBookView *object,
- GDBusMethodInvocation *invocation,
- const gchar * const *in_fields_of_interest,
- EDataBookView *view)
-{
- EDataBookViewPrivate *priv;
- gint ii;
-
- g_return_val_if_fail (in_fields_of_interest != NULL, TRUE);
-
- priv = view->priv;
-
- if (priv->fields_of_interest)
- g_hash_table_destroy (priv->fields_of_interest);
- priv->fields_of_interest = NULL;
-
- for (ii = 0; in_fields_of_interest[ii]; ii++) {
- const gchar *field = in_fields_of_interest[ii];
-
- if (!*field)
- continue;
-
- if (!priv->fields_of_interest)
- priv->fields_of_interest = g_hash_table_new_full (str_ic_hash, str_ic_equal, g_free, NULL);
-
- g_hash_table_insert (priv->fields_of_interest, g_strdup (field), GINT_TO_POINTER (1));
- }
-
- e_gdbus_book_view_complete_set_fields_of_interest (object, invocation, NULL);
-
- return TRUE;
-}
-
-static void
-reset_array (GArray *array)
-{
- gint i = 0;
- gchar *tmp = NULL;
-
- /* Free stored strings */
- for (i = 0; i < array->len; i++) {
- tmp = g_array_index (array, gchar *, i);
- g_free (tmp);
- }
-
- /* Force the array size to 0 */
- g_array_set_size (array, 0);
+ g_hash_table_insert (view->priv->ids, utf8_id, GUINT_TO_POINTER (1));
}
static gboolean
-id_is_in_view (EDataBookView *book_view,
+id_is_in_view (EDataBookView *view,
const gchar *id)
{
gchar *valid_id;
gboolean res;
- g_return_val_if_fail (book_view != NULL, FALSE);
+ g_return_val_if_fail (view != NULL, FALSE);
g_return_val_if_fail (id != NULL, FALSE);
valid_id = e_util_utf8_make_valid (id);
- res = g_hash_table_lookup (book_view->priv->ids, valid_id) != NULL;
+ res = g_hash_table_lookup (view->priv->ids, valid_id) != NULL;
g_free (valid_id);
return res;
/**
* e_data_book_view_notify_update:
- * @book_view: an #EDataBookView
+ * @view: an #EDataBookView
* @contact: an #EContact
*
* Notify listeners that @contact has changed. This can
* trigger an add, change or removal event depending on
* whether the change causes the contact to start matching,
* no longer match, or stay matching the query specified
- * by @book_view.
+ * by @view.
**/
void
-e_data_book_view_notify_update (EDataBookView *book_view,
+e_data_book_view_notify_update (EDataBookView *view,
const EContact *contact)
{
- EDataBookViewPrivate *priv = book_view->priv;
gboolean currently_in_view, want_in_view;
const gchar *id;
gchar *vcard;
- if (!priv->running)
+ g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
+ g_return_if_fail (E_IS_CONTACT (contact));
+
+ if (!view->priv->running)
return;
- g_mutex_lock (priv->pending_mutex);
+ g_mutex_lock (view->priv->pending_mutex);
id = e_contact_get_const ((EContact *) contact, E_CONTACT_UID);
- currently_in_view = id_is_in_view (book_view, id);
- want_in_view =
- e_book_backend_sexp_match_contact (priv->card_sexp, (EContact *) contact);
+ currently_in_view = id_is_in_view (view, id);
+ want_in_view = e_book_backend_sexp_match_contact (
+ view->priv->sexp, (EContact *) contact);
if (want_in_view) {
vcard = e_vcard_to_string (E_VCARD (contact),
EVC_FORMAT_VCARD_30);
if (currently_in_view)
- notify_change (book_view, id, vcard);
+ notify_change (view, id, vcard);
else
- notify_add (book_view, id, vcard);
+ notify_add (view, id, vcard);
g_free (vcard);
} else {
if (currently_in_view)
- notify_remove (book_view, id);
+ notify_remove (view, id);
/* else nothing; we're removing a card that wasn't there */
}
- g_mutex_unlock (priv->pending_mutex);
+ g_mutex_unlock (view->priv->pending_mutex);
}
/**
* e_data_book_view_notify_update_vcard:
- * @book_view: an #EDataBookView
+ * @view: an #EDataBookView
* @vcard: a plain vCard
*
* Notify listeners that @vcard has changed. This can
* trigger an add, change or removal event depending on
* whether the change causes the contact to start matching,
* no longer match, or stay matching the query specified
- * by @book_view. This method should be preferred over
+ * by @view. This method should be preferred over
* #e_data_book_view_notify_update when the native
* representation of a contact is a vCard.
**/
void
-e_data_book_view_notify_update_vcard (EDataBookView *book_view,
+e_data_book_view_notify_update_vcard (EDataBookView *view,
const gchar *id,
const gchar *vcard)
{
- EDataBookViewPrivate *priv = book_view->priv;
gboolean currently_in_view, want_in_view;
EContact *contact;
- if (!priv->running)
+ g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
+ g_return_if_fail (id != NULL);
+ g_return_if_fail (vcard != NULL);
+
+ if (!view->priv->running)
return;
- g_mutex_lock (priv->pending_mutex);
+ g_mutex_lock (view->priv->pending_mutex);
contact = e_contact_new_from_vcard_with_uid (vcard, id);
- currently_in_view = id_is_in_view (book_view, id);
- want_in_view =
- e_book_backend_sexp_match_contact (priv->card_sexp, contact);
+ currently_in_view = id_is_in_view (view, id);
+ want_in_view = e_book_backend_sexp_match_contact (
+ view->priv->sexp, contact);
if (want_in_view) {
if (currently_in_view)
- notify_change (book_view, id, vcard);
+ notify_change (view, id, vcard);
else
- notify_add (book_view, id, vcard);
+ notify_add (view, id, vcard);
} else {
if (currently_in_view)
- notify_remove (book_view, id);
+ notify_remove (view, id);
}
/* Do this last so that id is still valid when notify_ is called */
g_object_unref (contact);
- g_mutex_unlock (priv->pending_mutex);
+ g_mutex_unlock (view->priv->pending_mutex);
}
/**
* e_data_book_view_notify_update_prefiltered_vcard:
- * @book_view: an #EDataBookView
+ * @view: an #EDataBookView
* @id: the UID of this contact
* @vcard: a plain vCard
*
* trigger an add, change or removal event depending on
* whether the change causes the contact to start matching,
* no longer match, or stay matching the query specified
- * by @book_view. This method should be preferred over
+ * by @view. This method should be preferred over
* #e_data_book_view_notify_update when the native
* representation of a contact is a vCard.
*
* known to exist in the view.
**/
void
-e_data_book_view_notify_update_prefiltered_vcard (EDataBookView *book_view,
+e_data_book_view_notify_update_prefiltered_vcard (EDataBookView *view,
const gchar *id,
const gchar *vcard)
{
- EDataBookViewPrivate *priv = book_view->priv;
gboolean currently_in_view;
- if (!priv->running)
+ g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
+ g_return_if_fail (id != NULL);
+ g_return_if_fail (vcard != NULL);
+
+ if (!view->priv->running)
return;
- g_mutex_lock (priv->pending_mutex);
+ g_mutex_lock (view->priv->pending_mutex);
- currently_in_view = id_is_in_view (book_view, id);
+ currently_in_view = id_is_in_view (view, id);
if (currently_in_view)
- notify_change (book_view, id, vcard);
+ notify_change (view, id, vcard);
else
- notify_add (book_view, id, vcard);
+ notify_add (view, id, vcard);
- g_mutex_unlock (priv->pending_mutex);
+ g_mutex_unlock (view->priv->pending_mutex);
}
/**
* e_data_book_view_notify_remove:
- * @book_view: an #EDataBookView
+ * @view: an #EDataBookView
* @id: a unique contact ID
*
* Notify listeners that a contact specified by @id
- * was removed from @book_view.
+ * was removed from @view.
**/
void
-e_data_book_view_notify_remove (EDataBookView *book_view,
+e_data_book_view_notify_remove (EDataBookView *view,
const gchar *id)
{
- if (!book_view->priv->running)
+ g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
+ g_return_if_fail (id != NULL);
+
+ if (!view->priv->running)
return;
- g_mutex_lock (book_view->priv->pending_mutex);
+ g_mutex_lock (view->priv->pending_mutex);
- if (id_is_in_view (book_view, id))
- notify_remove (book_view, id);
+ if (id_is_in_view (view, id))
+ notify_remove (view, id);
- g_mutex_unlock (book_view->priv->pending_mutex);
+ g_mutex_unlock (view->priv->pending_mutex);
}
/**
* e_data_book_view_notify_complete:
- * @book_view: an #EDataBookView
+ * @view: an #EDataBookView
* @error: the error of the query, if any
*
- * Notifies listeners that all pending updates on @book_view
+ * Notifies listeners that all pending updates on @view
* have been sent. The listener's information should now be
* in sync with the backend's.
**/
void
-e_data_book_view_notify_complete (EDataBookView *book_view,
+e_data_book_view_notify_complete (EDataBookView *view,
const GError *error)
{
- EDataBookViewPrivate *priv = book_view->priv;
gchar **strv_error;
- if (!priv->running)
+ g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
+
+ if (!view->priv->running)
return;
+
/* View is complete */
- priv->complete = TRUE;
+ view->priv->complete = TRUE;
- g_mutex_lock (priv->pending_mutex);
+ g_mutex_lock (view->priv->pending_mutex);
- send_pending_adds (book_view);
- send_pending_changes (book_view);
- send_pending_removes (book_view);
+ send_pending_adds (view);
+ send_pending_changes (view);
+ send_pending_removes (view);
- g_mutex_unlock (priv->pending_mutex);
+ g_mutex_unlock (view->priv->pending_mutex);
strv_error = e_gdbus_templates_encode_error (error);
- e_gdbus_book_view_emit_complete (priv->gdbus_object, (const gchar * const *) strv_error);
+ e_gdbus_book_view_emit_complete (
+ view->priv->gdbus_object,
+ (const gchar * const *) strv_error);
g_strfreev (strv_error);
}
/**
* e_data_book_view_notify_progress:
- * @book_view: an #EDataBookView
+ * @view: an #EDataBookView
* @percent: percent done; use -1 when not available
* @message: a text message
*
* Since: 3.2
**/
void
-e_data_book_view_notify_progress (EDataBookView *book_view,
+e_data_book_view_notify_progress (EDataBookView *view,
guint percent,
const gchar *message)
{
gchar *gdbus_message = NULL;
- if (!book_view->priv->running)
+ g_return_if_fail (E_IS_DATA_BOOK_VIEW (view));
+
+ if (!view->priv->running)
return;
e_gdbus_book_view_emit_progress (
- book_view->priv->gdbus_object, percent,
+ view->priv->gdbus_object, percent,
e_util_ensure_gdbus_string (message, &gdbus_message));
g_free (gdbus_message);
}
/**
- * e_data_book_view_new:
- * @book: The #EDataBook to search
- * @card_query: The query as a string
- * @card_sexp: The query as an #EBookBackendSExp
- *
- * Create a new #EDataBookView for the given #EBook, filtering on #card_sexp,
- * and place it on DBus at the object path #path.
- */
-EDataBookView *
-e_data_book_view_new (EDataBook *book,
- const gchar *card_query,
- EBookBackendSExp *card_sexp)
-{
- EDataBookView *view;
- EDataBookViewPrivate *priv;
-
- view = g_object_new (E_TYPE_DATA_BOOK_VIEW, NULL);
- priv = view->priv;
-
- priv->book = book;
- /* Attach a weak reference to the book, so if it dies the book view is destroyed too */
- g_object_weak_ref (G_OBJECT (priv->book), book_destroyed_cb, view);
- priv->backend = g_object_ref (e_data_book_get_backend (book));
- priv->card_query = e_util_utf8_make_valid (card_query);
- priv->card_sexp = card_sexp;
-
- return view;
-}
-
-static gpointer
-bookview_start_thread (gpointer data)
-{
- EDataBookView *book_view = data;
-
- if (book_view->priv->running)
- e_book_backend_start_view (book_view->priv->backend, book_view);
- g_object_unref (book_view);
-
- return NULL;
-}
-
-static gboolean
-impl_DataBookView_start (EGdbusBookView *object,
- GDBusMethodInvocation *invocation,
- EDataBookView *book_view)
-{
- GThread *thread;
-
- book_view->priv->running = TRUE;
- book_view->priv->complete = FALSE;
-
- thread = g_thread_new (NULL, bookview_start_thread, g_object_ref (book_view));
- g_thread_unref (thread);
-
- e_gdbus_book_view_complete_start (object, invocation, NULL);
-
- return TRUE;
-}
-
-static gpointer
-bookview_stop_thread (gpointer data)
-{
- EDataBookView *book_view = data;
-
- if (!book_view->priv->running)
- e_book_backend_stop_view (book_view->priv->backend, book_view);
- g_object_unref (book_view);
-
- return NULL;
-}
-
-static gboolean
-impl_DataBookView_stop (EGdbusBookView *object,
- GDBusMethodInvocation *invocation,
- EDataBookView *book_view)
-{
- GThread *thread;
-
- book_view->priv->running = FALSE;
- book_view->priv->complete = FALSE;
-
- thread = g_thread_new (NULL, bookview_stop_thread, g_object_ref (book_view));
- g_thread_unref (thread);
-
- e_gdbus_book_view_complete_stop (object, invocation, NULL);
-
- return TRUE;
-}
-
-static gboolean
-impl_DataBookView_setFlags (EGdbusBookView *object,
- GDBusMethodInvocation *invocation,
- EBookClientViewFlags flags,
- EDataBookView *book_view)
-{
- book_view->priv->flags = flags;
-
- e_gdbus_book_view_complete_set_flags (object, invocation, NULL);
-
- return TRUE;
-}
-
-static gboolean
-impl_DataBookView_dispose (EGdbusBookView *object,
- GDBusMethodInvocation *invocation,
- EDataBookView *book_view)
-{
- e_gdbus_book_view_complete_dispose (object, invocation, NULL);
-
- e_book_backend_stop_view (book_view->priv->backend, book_view);
- book_view->priv->running = FALSE;
- e_book_backend_remove_view (book_view->priv->backend, book_view);
-
- g_object_unref (book_view);
-
- return TRUE;
-}
-
-static void
-e_data_book_view_init (EDataBookView *book_view)
-{
- book_view->priv = E_DATA_BOOK_VIEW_GET_PRIVATE (book_view);
-
- book_view->priv->flags = E_BOOK_CLIENT_VIEW_FLAGS_NOTIFY_INITIAL;
-
- book_view->priv->gdbus_object = e_gdbus_book_view_stub_new ();
- g_signal_connect (
- book_view->priv->gdbus_object, "handle-start",
- G_CALLBACK (impl_DataBookView_start), book_view);
- g_signal_connect (
- book_view->priv->gdbus_object, "handle-stop",
- G_CALLBACK (impl_DataBookView_stop), book_view);
- g_signal_connect (
- book_view->priv->gdbus_object, "handle-set-flags",
- G_CALLBACK (impl_DataBookView_setFlags), book_view);
- g_signal_connect (
- book_view->priv->gdbus_object, "handle-dispose",
- G_CALLBACK (impl_DataBookView_dispose), book_view);
- g_signal_connect (
- book_view->priv->gdbus_object, "handle-set-fields-of-interest",
- G_CALLBACK (impl_DataBookView_set_fields_of_interest), book_view);
-
- book_view->priv->fields_of_interest = NULL;
- book_view->priv->running = FALSE;
- book_view->priv->complete = FALSE;
- book_view->priv->pending_mutex = g_mutex_new ();
-
- /* THRESHOLD_ITEMS * 2 because we store UID and vcard */
- book_view->priv->adds = g_array_sized_new (
- TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS * 2);
- book_view->priv->changes = g_array_sized_new (
- TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS * 2);
- book_view->priv->removes = g_array_sized_new (
- TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS);
-
- book_view->priv->ids = g_hash_table_new_full (
- (GHashFunc) g_str_hash,
- (GEqualFunc) g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) NULL);
-
- book_view->priv->flush_id = 0;
-}
-
-static void
-e_data_book_view_dispose (GObject *object)
-{
- EDataBookView *book_view = E_DATA_BOOK_VIEW (object);
- EDataBookViewPrivate *priv = book_view->priv;
-
- if (priv->book) {
- /* Remove the weak reference */
- g_object_weak_unref (G_OBJECT (priv->book), book_destroyed_cb, book_view);
- priv->book = NULL;
- }
-
- if (priv->backend) {
- g_object_unref (priv->backend);
- priv->backend = NULL;
- }
-
- if (priv->card_sexp) {
- g_object_unref (priv->card_sexp);
- priv->card_sexp = NULL;
- }
-
- g_mutex_lock (priv->pending_mutex);
-
- if (priv->flush_id) {
- g_source_remove (priv->flush_id);
- priv->flush_id = 0;
- }
-
- g_mutex_unlock (priv->pending_mutex);
-
- G_OBJECT_CLASS (e_data_book_view_parent_class)->dispose (object);
-}
-
-static void
-e_data_book_view_finalize (GObject *object)
-{
- EDataBookView *book_view = E_DATA_BOOK_VIEW (object);
- EDataBookViewPrivate *priv = book_view->priv;
-
- reset_array (priv->adds);
- reset_array (priv->changes);
- reset_array (priv->removes);
- g_array_free (priv->adds, TRUE);
- g_array_free (priv->changes, TRUE);
- g_array_free (priv->removes, TRUE);
- g_free (priv->card_query);
-
- if (priv->fields_of_interest)
- g_hash_table_destroy (priv->fields_of_interest);
-
- g_mutex_free (priv->pending_mutex);
-
- g_hash_table_destroy (priv->ids);
-
- G_OBJECT_CLASS (e_data_book_view_parent_class)->finalize (object);
-}
-
-/**
- * e_data_book_view_get_card_query:
- * @book_view: an #EDataBookView
- *
- * Gets the text representation of the s-expression used
- * for matching contacts to @book_view.
- *
- * Returns: The textual s-expression used.
- **/
-const gchar *
-e_data_book_view_get_card_query (EDataBookView *book_view)
-{
- g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
-
- return book_view->priv->card_query;
-}
-
-/**
- * e_data_book_view_get_card_sexp:
- * @book_view: an #EDataBookView
- *
- * Gets the s-expression used for matching contacts to
- * @book_view.
- *
- * Returns: The #EBookBackendSExp used.
- **/
-EBookBackendSExp *
-e_data_book_view_get_card_sexp (EDataBookView *book_view)
-{
- g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
-
- return book_view->priv->card_sexp;
-}
-
-/**
- * e_data_book_view_get_backend:
- * @book_view: an #EDataBookView
- *
- * Gets the backend that @book_view is querying.
- *
- * Returns: The associated #EBookBackend.
- **/
-EBookBackend *
-e_data_book_view_get_backend (EDataBookView *book_view)
-{
- g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
-
- return book_view->priv->backend;
-}
-
-/**
- * e_data_book_view_get_flags:
- * @book_view: an #EDataBookView
- *
- * Gets the #EBookClientViewFlags that control the behaviour of @book_view.
- *
- * Returns: the flags for @book_view.
- *
- * Since: 3.4
- **/
-EBookClientViewFlags
-e_data_book_view_get_flags (EDataBookView *book_view)
-{
- g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), 0);
-
- return book_view->priv->flags;
-}
-
-/**
* e_data_book_view_get_fields_of_interest:
- * @view: A view object.
+ * @view: an #EDataBookView
*
* Returns: Hash table of field names which the listener is interested in.
* Backends can return fully populated objects, but the listener advertised
* only GINT_TO_POINTER(1) for easier checking. Also, field names are
* compared case insensitively.
**/
-/* const */ GHashTable *
+GHashTable *
e_data_book_view_get_fields_of_interest (EDataBookView *view)
{
g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);