dc271f196504f66b1ce348815e7707abbc5f0d79
[platform/upstream/evolution-data-server.git] / addressbook / libebook / e-book-client-view.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4  * Copyright (C) 2006 OpenedHand Ltd
5  * Copyright (C) 2009 Intel Corporation
6  *
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.
10  *
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
14  * details.
15  *
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
19  *
20  * Author: Ross Burton <ross@linux.intel.com>
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <glib/gi18n-lib.h>
28
29 #include "e-book-client.h"
30 #include "e-book-client-view.h"
31 #include "e-book-client-view-private.h"
32 #include "e-book-marshal.h"
33 #include "libedata-book/e-data-book-types.h"
34 #include "libedataserver/e-data-server-util.h"
35 #include "e-gdbus-book-view.h"
36
37 #define E_BOOK_CLIENT_VIEW_GET_PRIVATE(obj) \
38         (G_TYPE_INSTANCE_GET_PRIVATE \
39         ((obj), E_TYPE_BOOK_CLIENT_VIEW, EBookClientViewPrivate))
40
41 G_DEFINE_TYPE (EBookClientView, e_book_client_view, G_TYPE_OBJECT);
42
43 struct _EBookClientViewPrivate {
44         GDBusProxy *gdbus_bookview;
45         EBookClient *client;
46         gboolean running;
47 };
48
49 enum {
50         OBJECTS_ADDED,
51         OBJECTS_MODIFIED,
52         OBJECTS_REMOVED,
53         PROGRESS,
54         COMPLETE,
55         LAST_SIGNAL
56 };
57
58 static guint signals[LAST_SIGNAL];
59
60 static void
61 objects_added_cb (EGdbusBookView *object,
62                   const gchar * const *vcards,
63                   EBookClientView *view)
64 {
65         const gchar * const *p;
66         GSList *contacts = NULL;
67
68         if (!view->priv->running)
69                 return;
70
71         /* array contains both UID and vcard */
72         for (p = vcards; *p; p += 2) {
73                 contacts = g_slist_prepend (contacts, e_contact_new_from_vcard_with_uid (p[0], p[1]));
74         }
75
76         contacts = g_slist_reverse (contacts);
77
78         g_signal_emit (view, signals[OBJECTS_ADDED], 0, contacts);
79
80         e_util_free_object_slist (contacts);
81 }
82
83 static void
84 objects_modified_cb (EGdbusBookView *object,
85                      const gchar * const *vcards,
86                      EBookClientView *view)
87 {
88         const gchar * const *p;
89         GSList *contacts = NULL;
90
91         if (!view->priv->running)
92                 return;
93
94         /* array contains both UID and vcard */
95         for (p = vcards; *p; p += 2) {
96                 contacts = g_slist_prepend (contacts, e_contact_new_from_vcard_with_uid (p[0], p[1]));
97         }
98         contacts = g_slist_reverse (contacts);
99
100         g_signal_emit (view, signals[OBJECTS_MODIFIED], 0, contacts);
101
102         e_util_free_object_slist (contacts);
103 }
104
105 static void
106 objects_removed_cb (EGdbusBookView *object,
107                     const gchar * const *ids,
108                     EBookClientView *view)
109 {
110         const gchar * const *p;
111         GSList *list = NULL;
112
113         if (!view->priv->running)
114                 return;
115
116         for (p = ids; *p; p++) {
117                 list = g_slist_prepend (list, (gchar *) *p);
118         }
119         list = g_slist_reverse (list);
120
121         g_signal_emit (view, signals[OBJECTS_REMOVED], 0, list);
122
123         /* No need to free the values, our caller will */
124         g_slist_free (list);
125 }
126
127 static void
128 progress_cb (EGdbusBookView *object,
129              guint percent,
130              const gchar *message,
131              EBookClientView *view)
132 {
133         if (!view->priv->running)
134                 return;
135
136         g_signal_emit (view, signals[PROGRESS], 0, percent, message);
137 }
138
139 static void
140 complete_cb (EGdbusBookView *object,
141              const gchar * const *in_error_strv,
142              EBookClientView *view)
143 {
144         GError *error = NULL;
145
146         if (!view->priv->running)
147                 return;
148
149         g_return_if_fail (e_gdbus_templates_decode_error (in_error_strv, &error));
150
151         g_signal_emit (view, signals[COMPLETE], 0, error);
152
153         if (error)
154                 g_error_free (error);
155 }
156
157 /*
158  * _e_book_client_view_new:
159  * @book_client: an #EBookClient
160  * @gdbus_bookview: The #EGdbusBookView to get signals from
161  *
162  * Creates a new #EBookClientView based on #EBookClient and listening to @gdbus_bookview.
163  * This is a private function, applications should call e_book_client_get_view() or
164  * e_book_client_get_view_sync().
165  *
166  * Returns: A new #EBookClientView.
167  **/
168 EBookClientView *
169 _e_book_client_view_new (EBookClient *book_client,
170                          EGdbusBookView *gdbus_bookview)
171 {
172         EBookClientView *view;
173         EBookClientViewPrivate *priv;
174
175         view = g_object_new (E_TYPE_BOOK_CLIENT_VIEW, NULL);
176         priv = view->priv;
177
178         priv->client = g_object_ref (book_client);
179
180         /* Take ownership of the gdbus_bookview object */
181         priv->gdbus_bookview = g_object_ref (G_DBUS_PROXY (gdbus_bookview));
182
183         g_object_add_weak_pointer (G_OBJECT (gdbus_bookview), (gpointer) &priv->gdbus_bookview);
184         g_signal_connect (priv->gdbus_bookview, "objects-added", G_CALLBACK (objects_added_cb), view);
185         g_signal_connect (priv->gdbus_bookview, "objects-modified", G_CALLBACK (objects_modified_cb), view);
186         g_signal_connect (priv->gdbus_bookview, "objects-removed", G_CALLBACK (objects_removed_cb), view);
187         g_signal_connect (priv->gdbus_bookview, "progress", G_CALLBACK (progress_cb), view);
188         g_signal_connect (priv->gdbus_bookview, "complete", G_CALLBACK (complete_cb), view);
189
190         return view;
191 }
192
193 /**
194  * e_book_client_view_get_client:
195  * @view: an #EBookClientView
196  *
197  * Returns the #EBookClient that this book view is monitoring.
198  *
199  * Returns: (transfer none): an #EBookClient.
200  **/
201 EBookClient *
202 e_book_client_view_get_client (EBookClientView *view)
203 {
204         g_return_val_if_fail (E_IS_BOOK_CLIENT_VIEW (view), NULL);
205
206         return view->priv->client;
207 }
208
209 /**
210  * e_book_client_view_start:
211  * @error: A #GError
212  * @view: an #EBookClientView
213  *
214  * Tells @view to start processing events.
215  */
216 void
217 e_book_client_view_start (EBookClientView *view,
218                           GError **error)
219 {
220         EBookClientViewPrivate *priv;
221
222         g_return_if_fail (E_IS_BOOK_CLIENT_VIEW (view));
223
224         priv = view->priv;
225
226         if (priv->gdbus_bookview) {
227                 GError *local_error = NULL;
228
229                 priv->running = TRUE;
230                 if (!e_gdbus_book_view_call_start_sync (priv->gdbus_bookview, NULL, &local_error))
231                         priv->running = FALSE;
232
233                 e_client_unwrap_dbus_error (E_CLIENT (priv->client), local_error, error);
234         } else {
235                 /* do not translate this string, it should ideally never happen */
236                 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, "Cannot start view, D-Bus proxy gone");
237         }
238 }
239
240 /**
241  * e_book_client_view_stop:
242  * @view: an #EBookClientView
243  * @error: A #GError
244  *
245  * Tells @view to stop processing events.
246  **/
247 void
248 e_book_client_view_stop (EBookClientView *view,
249                          GError **error)
250 {
251         EBookClientViewPrivate *priv;
252
253         g_return_if_fail (E_IS_BOOK_CLIENT_VIEW (view));
254
255         priv = view->priv;
256         priv->running = FALSE;
257
258         if (priv->gdbus_bookview) {
259                 GError *local_error = NULL;
260
261                 e_gdbus_book_view_call_stop_sync (priv->gdbus_bookview, NULL, &local_error);
262
263                 e_client_unwrap_dbus_error (E_CLIENT (priv->client), local_error, error);
264         } else {
265                 /* do not translate this string, it should ideally never happen */
266                 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, "Cannot stop view, D-Bus proxy gone");
267         }
268 }
269
270 /**
271  * e_book_client_view_set_flags:
272  * @view: an #EBookClientView
273  * @flags: the #EBookClientViewFlags for @view.
274  * @error: a return location for a #GError, or %NULL.
275  *
276  * Sets the @flags which control the behaviour of @view.
277  *
278  * Since: 3.4
279  */
280 void
281 e_book_client_view_set_flags (EBookClientView *view,
282                               EBookClientViewFlags flags,
283                               GError **error)
284 {
285         EBookClientViewPrivate *priv;
286
287         g_return_if_fail (E_IS_BOOK_CLIENT_VIEW (view));
288
289         priv = view->priv;
290
291         if (priv->gdbus_bookview) {
292                 GError *local_error = NULL;
293
294                 e_gdbus_book_view_call_set_flags_sync (priv->gdbus_bookview, flags, NULL, &local_error);
295
296                 e_client_unwrap_dbus_error (E_CLIENT (priv->client), local_error, error);
297         } else {
298                 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR,
299                                      "Cannot set flags on view, D-Bus proxy gone");
300         }
301 }
302
303 /**
304  * e_book_client_view_set_fields_of_interest:
305  * @view: An #EBookClientView object
306  * @fields_of_interest: (element-type utf8): List of field names in which the client is interested
307  * @error: A #GError
308  *
309  * Client can instruct server to which fields it is interested in only, thus
310  * the server can return less data over the wire. The server can still return
311  * complete objects, this is just a hint to it that the listed fields will
312  * be used only. The UID field is returned always. Initial views has no fields
313  * of interest and using %NULL for @fields_of_interest will unset any previous
314  * changes.
315  *
316  * Some backends can use summary information of its cache to create artifical
317  * objects, which will omit stored object parsing. If this cannot be done then
318  * it will simply return object as is stored in the cache.
319  **/
320 void
321 e_book_client_view_set_fields_of_interest (EBookClientView *view,
322                                            const GSList *fields_of_interest,
323                                            GError **error)
324 {
325         EBookClientViewPrivate *priv;
326
327         g_return_if_fail (E_IS_BOOK_CLIENT_VIEW (view));
328
329         priv = view->priv;
330
331         if (priv->gdbus_bookview) {
332                 GError *local_error = NULL;
333                 gchar **strv;
334
335                 strv = e_client_util_slist_to_strv (fields_of_interest);
336                 e_gdbus_book_view_call_set_fields_of_interest_sync (priv->gdbus_bookview, (const gchar * const *) strv, NULL, &local_error);
337                 g_strfreev (strv);
338
339                 e_client_unwrap_dbus_error (E_CLIENT (priv->client), local_error, error);
340         } else {
341                 /* do not translate this string, it should ideally never happen */
342                 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, "Cannot set fields of interest, D-Bus proxy gone");
343         }
344 }
345
346 static void
347 e_book_client_view_init (EBookClientView *view)
348 {
349         view->priv = E_BOOK_CLIENT_VIEW_GET_PRIVATE (view);
350         view->priv->gdbus_bookview = NULL;
351
352         view->priv->client = NULL;
353         view->priv->running = FALSE;
354 }
355
356 static void
357 book_client_view_dispose (GObject *object)
358 {
359         EBookClientView *view = E_BOOK_CLIENT_VIEW (object);
360
361         if (view->priv->gdbus_bookview) {
362                 GError *error = NULL;
363
364                 g_signal_handlers_disconnect_matched (view->priv->gdbus_bookview, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view);
365                 e_gdbus_book_view_call_dispose_sync (G_DBUS_PROXY (view->priv->gdbus_bookview), NULL, &error);
366                 g_object_unref (view->priv->gdbus_bookview);
367                 view->priv->gdbus_bookview = NULL;
368
369                 if (error) {
370                         g_warning ("Failed to dispose book view: %s", error->message);
371                         g_error_free (error);
372                 }
373         }
374
375         if (view->priv->client) {
376                 g_object_unref (view->priv->client);
377                 view->priv->client = NULL;
378         }
379
380         /* Chain up to parent's dispose() method. */
381         G_OBJECT_CLASS (e_book_client_view_parent_class)->dispose (object);
382 }
383
384 static void
385 e_book_client_view_class_init (EBookClientViewClass *class)
386 {
387         GObjectClass *object_class;
388
389         g_type_class_add_private (class, sizeof (EBookClientViewPrivate));
390
391         object_class = G_OBJECT_CLASS (class);
392         object_class->dispose = book_client_view_dispose;
393
394         signals[OBJECTS_ADDED] =
395                 g_signal_new ("objects-added",
396                               G_OBJECT_CLASS_TYPE (object_class),
397                               G_SIGNAL_RUN_LAST,
398                               G_STRUCT_OFFSET (EBookClientViewClass, objects_added),
399                               NULL, NULL,
400                               g_cclosure_marshal_VOID__POINTER,
401                               G_TYPE_NONE, 1, G_TYPE_POINTER);
402
403         signals[OBJECTS_MODIFIED] =
404                 g_signal_new ("objects-modified",
405                               G_OBJECT_CLASS_TYPE (object_class),
406                               G_SIGNAL_RUN_LAST,
407                               G_STRUCT_OFFSET (EBookClientViewClass, objects_modified),
408                               NULL, NULL,
409                               g_cclosure_marshal_VOID__POINTER,
410                               G_TYPE_NONE, 1, G_TYPE_POINTER);
411
412         signals[OBJECTS_REMOVED] =
413                 g_signal_new ("objects-removed",
414                               G_OBJECT_CLASS_TYPE (object_class),
415                               G_SIGNAL_RUN_LAST,
416                               G_STRUCT_OFFSET (EBookClientViewClass, objects_removed),
417                               NULL, NULL,
418                               g_cclosure_marshal_VOID__POINTER,
419                               G_TYPE_NONE, 1, G_TYPE_POINTER);
420
421         signals[PROGRESS] =
422                 g_signal_new ("progress",
423                               G_OBJECT_CLASS_TYPE (object_class),
424                               G_SIGNAL_RUN_LAST,
425                               G_STRUCT_OFFSET (EBookClientViewClass, progress),
426                               NULL, NULL,
427                               e_gdbus_marshallers_VOID__UINT_STRING,
428                               G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
429
430         signals[COMPLETE] =
431                 g_signal_new ("complete",
432                               G_OBJECT_CLASS_TYPE (object_class),
433                               G_SIGNAL_RUN_LAST,
434                               G_STRUCT_OFFSET (EBookClientViewClass, complete),
435                               NULL, NULL,
436                               g_cclosure_marshal_VOID__BOXED,
437                               G_TYPE_NONE, 1, G_TYPE_ERROR);
438 }