Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-contact-list"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <libebook-contacts/libebook-contacts.h>
10 : : #include <libtracker-sparql/tracker-sparql.h>
11 : : #include <libvalent-core.h>
12 : :
13 : : #include "valent-contacts.h"
14 : : #include "valent-contact.h"
15 : :
16 : : #include "valent-contact-list.h"
17 : :
18 : : #define GET_CONTACT_RQ "/ca/andyholmes/Valent/sparql/get-contact.rq"
19 : : #define GET_CONTACT_LIST_RQ "/ca/andyholmes/Valent/sparql/get-contact-list.rq"
20 : :
21 : : /**
22 : : * ValentContactList:
23 : : *
24 : : * An abstract base class for address books.
25 : : *
26 : : * `ValentContactList` is a base class to provide an interface to an address
27 : : * book. This usually means adding, removing and querying contacts.
28 : : *
29 : : * Since: 1.0
30 : : */
31 : :
32 : : struct _ValentContactList
33 : : {
34 : : ValentResource parent_instance;
35 : :
36 : : TrackerSparqlConnection *connection;
37 : : TrackerNotifier *notifier;
38 : : TrackerSparqlStatement *get_contact_stmt;
39 : : TrackerSparqlStatement *get_contact_list_stmt;
40 : : GRegex *iri_pattern;
41 : : char *iri;
42 : : GCancellable *cancellable;
43 : :
44 : : /* list */
45 : : GSequence *items;
46 : : unsigned int last_position;
47 : : GSequenceIter *last_iter;
48 : : gboolean last_position_valid;
49 : : };
50 : :
51 : : static void g_list_model_iface_init (GListModelInterface *iface);
52 : :
53 : : static void valent_contact_list_load (ValentContactList *self);
54 : : static void valent_contact_list_load_contact (ValentContactList *self,
55 : : const char *iri);
56 : :
57 [ + + + - ]: 3853 : G_DEFINE_FINAL_TYPE_WITH_CODE (ValentContactList, valent_contact_list, VALENT_TYPE_RESOURCE,
58 : : G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, g_list_model_iface_init))
59 : :
60 : :
61 : : typedef enum {
62 : : PROP_CONNECTION = 1,
63 : : PROP_NOTIFIER,
64 : : } ValentContactListProperty;
65 : :
66 : : static GParamSpec *properties[PROP_NOTIFIER + 1] = { NULL, };
67 : :
68 : : static inline int
69 : 1 : valent_contact_list_lookup_func (gconstpointer a,
70 : : gconstpointer b,
71 : : gpointer user_data)
72 : : {
73 : 1 : const char *uid = e_contact_get_const ((EContact *)a, E_CONTACT_UID);
74 : 1 : const char *iri = g_strrstr ((const char *)b, uid);
75 : :
76 [ + - ]: 1 : if (iri == NULL)
77 : : return -1;
78 : :
79 : 1 : return g_utf8_collate (uid, iri);
80 : : }
81 : :
82 : : static void
83 : 1 : valent_contact_list_load_contact_cb (GObject *object,
84 : : GAsyncResult *result,
85 : : gpointer user_data)
86 : : {
87 : 1 : ValentContactList *self = VALENT_CONTACT_LIST (object);
88 : 1 : g_autoptr (EContact) contact = NULL;
89 : 1 : GSequenceIter *it;
90 : 1 : unsigned int position;
91 : 1 : g_autoptr (GError) error = NULL;
92 : :
93 : 1 : contact = g_task_propagate_pointer (G_TASK (result), &error);
94 [ - + ]: 1 : if (contact == NULL)
95 : : {
96 [ # # ]: 0 : if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
97 : : {
98 : 0 : const char *urn = g_task_get_task_data (G_TASK (result));
99 : 0 : g_warning ("%s(): %s: %s", G_STRFUNC, urn, error->message);
100 : : }
101 : :
102 [ # # ]: 0 : return;
103 : : }
104 : :
105 : 1 : it = g_sequence_append (self->items, g_object_ref (contact));
106 : 1 : position = g_sequence_iter_get_position (it);
107 [ - + ]: 1 : g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
108 : : }
109 : :
110 : : static void
111 : 1 : valent_contact_list_remove_contact (ValentContactList *self,
112 : : const char *iri)
113 : : {
114 : 1 : GSequenceIter *it;
115 : 1 : unsigned int position;
116 : :
117 [ + - ]: 1 : g_assert (VALENT_IS_CONTACT_LIST (self));
118 : :
119 : 1 : it = g_sequence_lookup (self->items,
120 : : (char *)iri,
121 : : valent_contact_list_lookup_func,
122 : : NULL);
123 : :
124 [ + - ]: 1 : if (it != NULL)
125 : : {
126 : 1 : position = g_sequence_iter_get_position (it);
127 : 1 : g_sequence_remove (it);
128 : 1 : g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 0);
129 : : }
130 : 1 : }
131 : :
132 : : gboolean
133 : 5 : valent_contact_list_event_is_contact (ValentContactList *self,
134 : : const char *iri)
135 : : {
136 : 0 : return g_regex_match (self->iri_pattern, iri, G_REGEX_MATCH_DEFAULT, NULL);
137 : : }
138 : :
139 : : static void
140 : 4 : on_notifier_event (TrackerNotifier *notifier,
141 : : const char *service,
142 : : const char *graph,
143 : : GPtrArray *events,
144 : : ValentContactList *self)
145 : : {
146 [ + - ]: 4 : g_assert (VALENT_IS_CONTACT_LIST (self));
147 : :
148 [ + - ]: 4 : if (g_strcmp0 (VALENT_CONTACTS_GRAPH, graph) != 0)
149 : : return;
150 : :
151 [ + + ]: 9 : for (unsigned int i = 0; i < events->len; i++)
152 : : {
153 : 5 : TrackerNotifierEvent *event = g_ptr_array_index (events, i);
154 : 5 : const char *urn = tracker_notifier_event_get_urn (event);
155 : :
156 [ + + ]: 5 : if (!valent_contact_list_event_is_contact (self, urn))
157 : 3 : continue;
158 : :
159 [ + + - - ]: 2 : switch (tracker_notifier_event_get_event_type (event))
160 : : {
161 : 1 : case TRACKER_NOTIFIER_EVENT_CREATE:
162 : 1 : VALENT_NOTE ("CREATE: %s", urn);
163 : 1 : valent_contact_list_load_contact (self, urn);
164 : 1 : break;
165 : :
166 : 1 : case TRACKER_NOTIFIER_EVENT_DELETE:
167 : 1 : VALENT_NOTE ("DELETE: %s", urn);
168 : 1 : valent_contact_list_remove_contact (self, urn);
169 : 1 : break;
170 : :
171 : : case TRACKER_NOTIFIER_EVENT_UPDATE:
172 : : VALENT_NOTE ("UPDATE: %s", urn);
173 : : // valent_contact_list_update_contact (self, urn);
174 : : break;
175 : :
176 : 0 : default:
177 : 5 : g_warn_if_reached ();
178 : : }
179 : : }
180 : : }
181 : :
182 : : #define CURSOR_CONTACT_IRI (0)
183 : : #define CURSOR_CONTACT_UID (1)
184 : : #define CURSOR_CONTACT_VCARD (2)
185 : :
186 : : static EContact *
187 : 31 : valent_contact_from_sparql_cursor (TrackerSparqlCursor *cursor)
188 : : {
189 : : // const char *iri = NULL;
190 : 31 : const char *uid = NULL;
191 : 31 : const char *vcard = NULL;
192 : :
193 [ + - ]: 31 : g_assert (TRACKER_IS_SPARQL_CURSOR (cursor));
194 : :
195 [ + - - + ]: 62 : if (!tracker_sparql_cursor_is_bound (cursor, CURSOR_CONTACT_UID) ||
196 : 31 : !tracker_sparql_cursor_is_bound (cursor, CURSOR_CONTACT_VCARD))
197 : 0 : g_return_val_if_reached (NULL);
198 : :
199 : : // iri = tracker_sparql_cursor_get_string (cursor, CURSOR_CONTACT_IRI, NULL);
200 : 31 : uid = tracker_sparql_cursor_get_string (cursor, CURSOR_CONTACT_UID, NULL);
201 : 31 : vcard = tracker_sparql_cursor_get_string (cursor, CURSOR_CONTACT_VCARD, NULL);
202 : :
203 : 31 : return e_contact_new_from_vcard_with_uid (vcard, uid);
204 : : }
205 : :
206 : : static void
207 : 1 : cursor_get_contact_cb (TrackerSparqlCursor *cursor,
208 : : GAsyncResult *result,
209 : : gpointer user_data)
210 : : {
211 : 1 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
212 : 1 : GError *error = NULL;
213 : :
214 [ + - ]: 1 : if (tracker_sparql_cursor_next_finish (cursor, result, &error))
215 : : {
216 : 1 : g_autoptr (EContact) contact = NULL;
217 : :
218 : 1 : contact = valent_contact_from_sparql_cursor (cursor);
219 : 1 : g_task_return_pointer (task, g_steal_pointer (&contact), g_object_unref);
220 : : }
221 : : else
222 : : {
223 [ # # ]: 0 : if (error == NULL)
224 : : {
225 : 0 : g_set_error_literal (&error,
226 : : G_IO_ERROR,
227 : : G_IO_ERROR_NOT_FOUND,
228 : : "Failed to find contact");
229 : : }
230 : :
231 : 0 : g_task_return_error (task, g_steal_pointer (&error));
232 : : }
233 : :
234 [ + - ]: 1 : tracker_sparql_cursor_close (cursor);
235 : 1 : }
236 : :
237 : : static void
238 : 1 : execute_get_contact_cb (TrackerSparqlStatement *stmt,
239 : : GAsyncResult *result,
240 : : gpointer user_data)
241 : : {
242 : 2 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
243 : 1 : GCancellable *cancellable = g_task_get_cancellable (task);
244 [ - - + - ]: 1 : g_autoptr (TrackerSparqlCursor) cursor = NULL;
245 : 1 : GError *error = NULL;
246 : :
247 : 1 : cursor = tracker_sparql_statement_execute_finish (stmt, result, &error);
248 [ - + ]: 1 : if (cursor == NULL)
249 : : {
250 : 0 : g_task_return_error (task, g_steal_pointer (&error));
251 [ # # ]: 0 : return;
252 : : }
253 : :
254 : 1 : tracker_sparql_cursor_next_async (cursor,
255 : : cancellable,
256 : : (GAsyncReadyCallback) cursor_get_contact_cb,
257 : : g_object_ref (task));
258 : : }
259 : :
260 : : static void
261 : 1 : valent_contact_list_load_contact (ValentContactList *self,
262 : : const char *iri)
263 : : {
264 : 1 : g_autoptr (GTask) task = NULL;
265 : 1 : GError *error = NULL;
266 : :
267 [ + - ]: 1 : g_assert (VALENT_IS_CONTACT_LIST (self));
268 [ - + ]: 1 : g_assert (iri != NULL);
269 : :
270 : 1 : task = g_task_new (self, self->cancellable, valent_contact_list_load_contact_cb, NULL);
271 [ + - ]: 1 : g_task_set_source_tag (task, valent_contact_list_load_contact);
272 : :
273 [ + - ]: 1 : if (self->get_contact_stmt == NULL)
274 : : {
275 : 1 : self->get_contact_stmt =
276 : 1 : tracker_sparql_connection_load_statement_from_gresource (self->connection,
277 : : GET_CONTACT_RQ,
278 : : self->cancellable,
279 : : &error);
280 : : }
281 : :
282 [ - + ]: 1 : if (self->get_contact_stmt == NULL)
283 : : {
284 : 0 : g_task_return_error (task, g_steal_pointer (&error));
285 [ # # ]: 0 : return;
286 : : }
287 : :
288 : 1 : tracker_sparql_statement_bind_string (self->get_contact_stmt, "iri", iri);
289 [ + - ]: 1 : tracker_sparql_statement_execute_async (self->get_contact_stmt,
290 : : self->cancellable,
291 : : (GAsyncReadyCallback) execute_get_contact_cb,
292 : : g_object_ref (task));
293 : : }
294 : :
295 : : static void
296 : 41 : cursor_get_contact_list_cb (TrackerSparqlCursor *cursor,
297 : : GAsyncResult *result,
298 : : gpointer user_data)
299 : : {
300 : 82 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
301 : 41 : ValentContactList *self = g_task_get_source_object (task);
302 : 41 : GPtrArray *contacts = g_task_get_task_data (task);
303 : 41 : GError *error = NULL;
304 : :
305 [ + + ]: 41 : if (tracker_sparql_cursor_next_finish (cursor, result, &error))
306 : : {
307 : 30 : EContact *contact = NULL;
308 : :
309 : 30 : contact = valent_contact_from_sparql_cursor (cursor);
310 [ + - ]: 30 : if (contact != NULL)
311 : 30 : g_ptr_array_add (contacts, g_steal_pointer (&contact));
312 : :
313 : 30 : tracker_sparql_cursor_next_async (cursor,
314 : : g_task_get_cancellable (task),
315 : : (GAsyncReadyCallback) cursor_get_contact_list_cb,
316 : : g_object_ref (task));
317 [ + - ]: 30 : return;
318 : : }
319 : :
320 [ - + - - ]: 11 : if (error != NULL && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
321 : : {
322 : 0 : g_warning ("%s(): %s: %s", G_STRFUNC, self->iri, error->message);
323 : : }
324 [ + + ]: 11 : else if (contacts->len > 0)
325 : : {
326 : 10 : unsigned int position = g_sequence_get_length (self->items);
327 : :
328 [ + + ]: 40 : for (unsigned int i = 0; i < contacts->len; i++)
329 : : {
330 : 30 : g_sequence_append (self->items,
331 : 30 : g_object_ref (g_ptr_array_index (contacts, i)));
332 : : }
333 : :
334 : 10 : g_list_model_items_changed (G_LIST_MODEL (self), position, 0, contacts->len);
335 : : }
336 : :
337 : 11 : g_task_return_boolean (task, TRUE);
338 [ + - ]: 11 : tracker_sparql_cursor_close (cursor);
339 : : }
340 : :
341 : : static void
342 : 11 : execute_get_contact_list_cb (TrackerSparqlStatement *stmt,
343 : : GAsyncResult *result,
344 : : gpointer user_data)
345 : : {
346 : 22 : g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
347 [ - - + - ]: 11 : g_autoptr (TrackerSparqlCursor) cursor = NULL;
348 : 11 : GError *error = NULL;
349 : :
350 : 11 : cursor = tracker_sparql_statement_execute_finish (stmt, result, &error);
351 [ - + ]: 11 : if (cursor == NULL)
352 : : {
353 : 0 : g_task_return_error (task, g_steal_pointer (&error));
354 [ # # ]: 0 : return;
355 : : }
356 : :
357 : 11 : tracker_sparql_cursor_next_async (cursor,
358 : : g_task_get_cancellable (G_TASK (result)),
359 : : (GAsyncReadyCallback) cursor_get_contact_list_cb,
360 : : g_object_ref (task));
361 : : }
362 : :
363 : : static void
364 : 11 : valent_contact_list_load (ValentContactList *self)
365 : : {
366 : 11 : g_autoptr (GTask) task = NULL;
367 [ + - ]: 11 : g_autoptr (GError) error = NULL;
368 : :
369 [ + - ]: 11 : g_assert (VALENT_IS_CONTACT_LIST (self));
370 [ - + ]: 11 : g_assert (TRACKER_IS_SPARQL_CONNECTION (self->connection));
371 : :
372 [ + - ]: 11 : if (self->get_contact_list_stmt == NULL)
373 : : {
374 : 11 : self->get_contact_list_stmt =
375 : 11 : tracker_sparql_connection_load_statement_from_gresource (self->connection,
376 : : GET_CONTACT_LIST_RQ,
377 : : self->cancellable,
378 : : &error);
379 : : }
380 : :
381 [ - + ]: 11 : if (self->get_contact_list_stmt == NULL)
382 : : {
383 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
384 [ # # ]: 0 : return;
385 : : }
386 : :
387 : 11 : task = g_task_new (self, self->cancellable, NULL, NULL);
388 [ + - ]: 11 : g_task_set_source_tag (task, valent_contact_list_load);
389 : 11 : g_task_set_task_data (task,
390 : 11 : g_ptr_array_new_with_free_func (g_object_unref),
391 : : (GDestroyNotify)g_ptr_array_unref);
392 : :
393 : 11 : tracker_sparql_statement_bind_string (self->get_contact_list_stmt, "iri",
394 : 11 : self->iri);
395 [ - + ]: 11 : tracker_sparql_statement_execute_async (self->get_contact_list_stmt,
396 : : g_task_get_cancellable (task),
397 : : (GAsyncReadyCallback) execute_get_contact_list_cb,
398 : : g_object_ref (task));
399 : : }
400 : :
401 : : /*
402 : : * GListModel
403 : : */
404 : : static gpointer
405 : 9 : valent_contact_list_get_item (GListModel *list,
406 : : unsigned int position)
407 : : {
408 : 9 : ValentContactList *self = VALENT_CONTACT_LIST (list);
409 : 9 : GSequenceIter *it = NULL;
410 : :
411 [ + - ]: 9 : g_assert (VALENT_IS_CONTACT_LIST (self));
412 : :
413 [ + + ]: 9 : if (self->last_position_valid)
414 : : {
415 [ + - - + ]: 7 : if (position < G_MAXUINT && self->last_position == position + 1)
416 : 0 : it = g_sequence_iter_prev (self->last_iter);
417 [ + + + - ]: 7 : else if (position > 0 && self->last_position == position - 1)
418 : 6 : it = g_sequence_iter_next (self->last_iter);
419 [ - + ]: 1 : else if (self->last_position == position)
420 : 0 : it = self->last_iter;
421 : : }
422 : :
423 [ - + ]: 6 : if (it == NULL)
424 : 3 : it = g_sequence_get_iter_at_pos (self->items, position);
425 : :
426 : 9 : self->last_iter = it;
427 : 9 : self->last_position = position;
428 : 9 : self->last_position_valid = TRUE;
429 : :
430 [ + - ]: 9 : if (g_sequence_iter_is_end (it))
431 : : return NULL;
432 : :
433 : 9 : return g_object_ref (g_sequence_get (it));
434 : : }
435 : :
436 : : static GType
437 : 1 : valent_contact_list_get_item_type (GListModel *list)
438 : : {
439 : 1 : return E_TYPE_CONTACT;
440 : : }
441 : :
442 : : static unsigned int
443 : 3808 : valent_contact_list_get_n_items (GListModel *list)
444 : : {
445 : 3808 : ValentContactList *self = VALENT_CONTACT_LIST (list);
446 : :
447 [ + - ]: 3808 : g_assert (VALENT_IS_CONTACT_LIST (self));
448 : :
449 : 3808 : return g_sequence_get_length (self->items);
450 : : }
451 : :
452 : : static void
453 : 4 : g_list_model_iface_init (GListModelInterface *iface)
454 : : {
455 : 4 : iface->get_item = valent_contact_list_get_item;
456 : 4 : iface->get_item_type = valent_contact_list_get_item_type;
457 : 4 : iface->get_n_items = valent_contact_list_get_n_items;
458 : 4 : }
459 : :
460 : : /*
461 : : * GObject
462 : : */
463 : : static void
464 : 11 : valent_contact_list_constructed (GObject *object)
465 : : {
466 : 11 : ValentContactList *self = VALENT_CONTACT_LIST (object);
467 : :
468 : 11 : G_OBJECT_CLASS (valent_contact_list_parent_class)->constructed (object);
469 : :
470 : 11 : self->cancellable = valent_object_ref_cancellable (VALENT_OBJECT (self));
471 : 11 : g_object_get (VALENT_OBJECT (self), "iri", &self->iri, NULL);
472 : :
473 [ + - - + ]: 11 : if (self->connection != NULL && self->notifier == NULL)
474 : 0 : self->notifier = tracker_sparql_connection_create_notifier (self->connection);
475 : :
476 [ + - ]: 11 : if (self->notifier != NULL)
477 : : {
478 : 11 : g_autofree char *iri_pattern = NULL;
479 : :
480 : 11 : g_signal_connect_object (self->notifier,
481 : : "events",
482 : : G_CALLBACK (on_notifier_event),
483 : : self,
484 : : G_CONNECT_DEFAULT);
485 : :
486 : 11 : iri_pattern = g_strdup_printf ("^%s:([^:]+)$", self->iri);
487 : 11 : self->iri_pattern = g_regex_new (iri_pattern,
488 : : G_REGEX_OPTIMIZE,
489 : : G_REGEX_MATCH_DEFAULT,
490 : : NULL);
491 : :
492 : 11 : valent_contact_list_load (self);
493 : : }
494 : 11 : }
495 : :
496 : : static void
497 : 9 : valent_contact_list_destroy (ValentObject *object)
498 : : {
499 : 9 : ValentContactList *self = VALENT_CONTACT_LIST (object);
500 : :
501 : 9 : g_signal_handlers_disconnect_by_func (self->notifier, on_notifier_event, self);
502 : :
503 : 9 : VALENT_OBJECT_CLASS (valent_contact_list_parent_class)->destroy (object);
504 : 9 : }
505 : :
506 : : static void
507 : 9 : valent_contact_list_finalize (GObject *object)
508 : : {
509 : 9 : ValentContactList *self = VALENT_CONTACT_LIST (object);
510 : :
511 [ + - ]: 9 : g_clear_object (&self->connection);
512 [ + - ]: 9 : g_clear_pointer (&self->iri, g_free);
513 [ + - ]: 9 : g_clear_object (&self->notifier);
514 [ + + ]: 9 : g_clear_object (&self->get_contact_stmt);
515 [ + - ]: 9 : g_clear_object (&self->get_contact_list_stmt);
516 [ + - ]: 9 : g_clear_pointer (&self->iri_pattern, g_regex_unref);
517 [ + - ]: 9 : g_clear_object (&self->cancellable);
518 [ + - ]: 9 : g_clear_pointer (&self->items, g_sequence_free);
519 : :
520 : 9 : G_OBJECT_CLASS (valent_contact_list_parent_class)->finalize (object);
521 : 9 : }
522 : :
523 : :
524 : : static void
525 : 1 : valent_contact_list_get_property (GObject *object,
526 : : guint prop_id,
527 : : GValue *value,
528 : : GParamSpec *pspec)
529 : : {
530 : 1 : ValentContactList *self = VALENT_CONTACT_LIST (object);
531 : :
532 [ + - - ]: 1 : switch ((ValentContactListProperty)prop_id)
533 : : {
534 : 1 : case PROP_CONNECTION:
535 : 1 : g_value_set_object (value, self->connection);
536 : 1 : break;
537 : :
538 : 0 : case PROP_NOTIFIER:
539 : 0 : g_value_set_object (value, self->notifier);
540 : 0 : break;
541 : :
542 : 0 : default:
543 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
544 : : }
545 : 1 : }
546 : :
547 : : static void
548 : 22 : valent_contact_list_set_property (GObject *object,
549 : : guint prop_id,
550 : : const GValue *value,
551 : : GParamSpec *pspec)
552 : : {
553 : 22 : ValentContactList *self = VALENT_CONTACT_LIST (object);
554 : :
555 [ + + - ]: 22 : switch ((ValentContactListProperty)prop_id)
556 : : {
557 : 11 : case PROP_CONNECTION:
558 : 11 : self->connection = g_value_dup_object (value);
559 : 11 : break;
560 : :
561 : 11 : case PROP_NOTIFIER:
562 : 11 : self->notifier = g_value_dup_object (value);
563 : 11 : break;
564 : :
565 : 0 : default:
566 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
567 : : }
568 : 22 : }
569 : :
570 : : static void
571 : 4 : valent_contact_list_class_init (ValentContactListClass *klass)
572 : : {
573 : 4 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
574 : 4 : ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
575 : :
576 : 4 : object_class->constructed = valent_contact_list_constructed;
577 : 4 : object_class->finalize = valent_contact_list_finalize;
578 : 4 : object_class->get_property = valent_contact_list_get_property;
579 : 4 : object_class->set_property = valent_contact_list_set_property;
580 : :
581 : 4 : vobject_class->destroy = valent_contact_list_destroy;
582 : :
583 : 8 : properties [PROP_CONNECTION] =
584 : 4 : g_param_spec_object ("connection", NULL, NULL,
585 : : TRACKER_TYPE_SPARQL_CONNECTION,
586 : : (G_PARAM_READWRITE |
587 : : G_PARAM_CONSTRUCT_ONLY |
588 : : G_PARAM_EXPLICIT_NOTIFY |
589 : : G_PARAM_STATIC_STRINGS));
590 : :
591 : 8 : properties [PROP_NOTIFIER] =
592 : 4 : g_param_spec_object ("notifier", NULL, NULL,
593 : : TRACKER_TYPE_NOTIFIER,
594 : : (G_PARAM_READWRITE |
595 : : G_PARAM_CONSTRUCT_ONLY |
596 : : G_PARAM_EXPLICIT_NOTIFY |
597 : : G_PARAM_STATIC_STRINGS));
598 : :
599 : 4 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
600 : 4 : }
601 : :
602 : : static void
603 : 11 : valent_contact_list_init (ValentContactList *self)
604 : : {
605 : 11 : self->items = g_sequence_new (g_object_unref);
606 : 11 : }
607 : :
608 : :
|