No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | e-addressbook-model.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-addressbook-model.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Christopher James Lahey <clahey@ximian.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28 #include <glib/gi18n.h>
29 #include "e-addressbook-model.h"
30 #include <e-util/e-marshal.h>
31 #include <e-util/e-util.h>
32 #include "eab-gui-util.h"
33
34 #define E_ADDRESSBOOK_MODEL_GET_PRIVATE(obj) \
35 (G_TYPE_INSTANCE_GET_PRIVATE \
36 ((obj), E_TYPE_ADDRESSBOOK_MODEL, EAddressbookModelPrivate))
37
38 struct _EAddressbookModelPrivate {
39 ESourceRegistry *registry;
40 EBookClient *book_client;
41 gchar *query_str;
42 EBookClientView *client_view;
43 guint client_view_idle_id;
44
45 /* Query Results */
46 GPtrArray *contacts;
47
48 /* Signal Handler IDs */
49 gulong create_contact_id;
50 gulong remove_contact_id;
51 gulong modify_contact_id;
52 gulong status_message_id;
53 gulong writable_status_id;
54 gulong view_complete_id;
55 gulong backend_died_id;
56 guint remove_status_id;
57
58 guint search_in_progress : 1;
59 guint editable : 1;
60 guint first_get_view : 1;
61 };
62
63 enum {
64 PROP_0,
65 PROP_CLIENT,
66 PROP_EDITABLE,
67 PROP_QUERY,
68 PROP_REGISTRY
69 };
70
71 enum {
72 WRITABLE_STATUS,
73 STATUS_MESSAGE,
74 SEARCH_STARTED,
75 SEARCH_RESULT,
76 FOLDER_BAR_MESSAGE,
77 CONTACT_ADDED,
78 CONTACTS_REMOVED,
79 CONTACT_CHANGED,
80 MODEL_CHANGED,
81 STOP_STATE_CHANGED,
82 BACKEND_DIED,
83 LAST_SIGNAL
84 };
85
86 static guint signals[LAST_SIGNAL];
87
88 G_DEFINE_TYPE (EAddressbookModel, e_addressbook_model, G_TYPE_OBJECT)
89
90 static void
91 free_data (EAddressbookModel *model)
92 {
93 GPtrArray *array;
94
95 array = model->priv->contacts;
96 g_ptr_array_foreach (array, (GFunc) g_object_unref, NULL);
97 g_ptr_array_set_size (array, 0);
98 }
99
100 static void
101 remove_book_view (EAddressbookModel *model)
102 {
103 if (model->priv->client_view && model->priv->create_contact_id)
104 g_signal_handler_disconnect (
105 model->priv->client_view,
106 model->priv->create_contact_id);
107 if (model->priv->client_view && model->priv->remove_contact_id)
108 g_signal_handler_disconnect (
109 model->priv->client_view,
110 model->priv->remove_contact_id);
111 if (model->priv->client_view && model->priv->modify_contact_id)
112 g_signal_handler_disconnect (
113 model->priv->client_view,
114 model->priv->modify_contact_id);
115 if (model->priv->client_view && model->priv->status_message_id)
116 g_signal_handler_disconnect (
117 model->priv->client_view,
118 model->priv->status_message_id);
119 if (model->priv->client_view && model->priv->view_complete_id)
120 g_signal_handler_disconnect (
121 model->priv->client_view,
122 model->priv->view_complete_id);
123 if (model->priv->remove_status_id)
124 g_source_remove (model->priv->remove_status_id);
125
126 model->priv->create_contact_id = 0;
127 model->priv->remove_contact_id = 0;
128 model->priv->modify_contact_id = 0;
129 model->priv->status_message_id = 0;
130 model->priv->view_complete_id = 0;
131 model->priv->remove_status_id = 0;
132
133 model->priv->search_in_progress = FALSE;
134
135 if (model->priv->client_view) {
136 GError *error = NULL;
137
138 e_book_client_view_stop (model->priv->client_view, &error);
139
140 if (error != NULL) {
141 g_warning (
142 "%s: Failed to stop client view: %s",
143 G_STRFUNC, error->message);
144 g_error_free (error);
145 }
146
147 g_object_unref (model->priv->client_view);
148 model->priv->client_view = NULL;
149
150 g_signal_emit (model, signals[STATUS_MESSAGE], 0, NULL, -1);
151 }
152 }
153
154 static void
155 update_folder_bar_message (EAddressbookModel *model)
156 {
157 guint count;
158 gchar *message;
159
160 count = model->priv->contacts->len;
161
162 switch (count) {
163 case 0:
164 message = g_strdup (_("No contacts"));
165 break;
166 default:
167 message = g_strdup_printf (
168 ngettext ("%d contact", "%d contacts", count), count);
169 break;
170 }
171
172 g_signal_emit (model, signals[FOLDER_BAR_MESSAGE], 0, message);
173
174 g_free (message);
175 }
176
177 static void
178 view_create_contact_cb (EBookClientView *client_view,
179 const GSList *contact_list,
180 EAddressbookModel *model)
181 {
182 GPtrArray *array;
183 guint count;
184 guint index;
185
186 array = model->priv->contacts;
187 index = array->len;
188 count = g_list_length ((GList *) contact_list);
189
190 while (contact_list != NULL) {
191 EContact *contact = contact_list->data;
192
193 g_ptr_array_add (array, g_object_ref (contact));
194 contact_list = contact_list->next;
195 }
196
197 g_signal_emit (model, signals[CONTACT_ADDED], 0, index, count);
198 update_folder_bar_message (model);
199 }
200
201 static gint
202 sort_descending (gconstpointer ca,
203 gconstpointer cb)
204 {
205 gint a = *((gint *) ca);
206 gint b = *((gint *) cb);
207
208 return (a == b) ? 0 : (a < b) ? 1 : -1;
209 }
210
211 static void
212 view_remove_contact_cb (EBookClientView *client_view,
213 const GSList *ids,
214 EAddressbookModel *model)
215 {
216 /* XXX we should keep a hash around instead of this O(n*m) loop */
217 const GSList *iter;
218 GArray *indices;
219 GPtrArray *array;
220 gint ii;
221
222 array = model->priv->contacts;
223 indices = g_array_new (FALSE, FALSE, sizeof (gint));
224
225 for (iter = ids; iter != NULL; iter = iter->next) {
226 const gchar *target_uid = iter->data;
227
228 for (ii = 0; ii < array->len; ii++) {
229 EContact *contact;
230 const gchar *uid;
231
232 contact = array->pdata[ii];
233 /* check if already removed */
234 if (!contact)
235 continue;
236
237 uid = e_contact_get_const (contact, E_CONTACT_UID);
238 g_return_if_fail (uid != NULL);
239
240 if (strcmp (uid, target_uid) == 0) {
241 g_object_unref (contact);
242 g_array_append_val (indices, ii);
243 array->pdata[ii] = NULL;
244 break;
245 }
246 }
247 }
248
249 /* Sort the 'indices' array in descending order, since
250 * g_ptr_array_remove_index() shifts subsequent elements
251 * down one position to fill the gap. */
252 g_array_sort (indices, sort_descending);
253
254 for (ii = 0; ii < indices->len; ii++) {
255 gint index;
256
257 index = g_array_index (indices, gint, ii);
258 g_ptr_array_remove_index (array, index);
259 }
260
261 g_signal_emit (model, signals[CONTACTS_REMOVED], 0, indices);
262 g_array_free (indices, FALSE);
263
264 update_folder_bar_message (model);
265 }
266
267 static void
268 view_modify_contact_cb (EBookClientView *client_view,
269 const GSList *contact_list,
270 EAddressbookModel *model)
271 {
272 GPtrArray *array;
273
274 array = model->priv->contacts;
275
276 while (contact_list != NULL) {
277 EContact *new_contact = contact_list->data;
278 const gchar *target_uid;
279 gint ii;
280
281 target_uid = e_contact_get_const (new_contact, E_CONTACT_UID);
282 g_warn_if_fail (target_uid != NULL);
283
284 /* skip contacts without UID */
285 if (!target_uid) {
286 contact_list = contact_list->next;
287 continue;
288 }
289
290 for (ii = 0; ii < array->len; ii++) {
291 EContact *old_contact;
292 const gchar *uid;
293
294 old_contact = array->pdata[ii];
295 g_return_if_fail (old_contact != NULL);
296
297 uid = e_contact_get_const (old_contact, E_CONTACT_UID);
298 g_return_if_fail (uid != NULL);
299
300 if (strcmp (uid, target_uid) != 0)
301 continue;
302
303 g_object_unref (old_contact);
304 array->pdata[ii] = e_contact_duplicate (new_contact);
305
306 g_signal_emit (
307 model, signals[CONTACT_CHANGED], 0, ii);
308 break;
309 }
310
311 contact_list = contact_list->next;
312 }
313 }
314
315 static void
316 view_progress_cb (EBookClientView *client_view,
317 guint percent,
318 const gchar *message,
319 EAddressbookModel *model)
320 {
321 if (model->priv->remove_status_id)
322 g_source_remove (model->priv->remove_status_id);
323 model->priv->remove_status_id = 0;
324
325 g_signal_emit (model, signals[STATUS_MESSAGE], 0, message, percent);
326 }
327
328 static void
329 view_complete_cb (EBookClientView *client_view,
330 const GError *error,
331 EAddressbookModel *model)
332 {
333 model->priv->search_in_progress = FALSE;
334 view_progress_cb (client_view, -1, NULL, model);
335 g_signal_emit (model, signals[SEARCH_RESULT], 0, error);
336 g_signal_emit (model, signals[STOP_STATE_CHANGED], 0);
337 }
338
339 static void
340 readonly_cb (EBookClient *book_client,
341 GParamSpec *pspec,
342 EAddressbookModel *model)
343 {
344 gboolean editable;
345
346 editable = !e_client_is_readonly (E_CLIENT (book_client));
347 e_addressbook_model_set_editable (model, editable);
348 }
349
350 static void
351 backend_died_cb (EBookClient *book_client,
352 EAddressbookModel *model)
353 {
354 g_signal_emit (model, signals[BACKEND_DIED], 0);
355 }
356
357 static void
358 client_view_ready_cb (GObject *source_object,
359 GAsyncResult *result,
360 gpointer user_data)
361 {
362 EBookClient *book_client = E_BOOK_CLIENT (source_object);
363 EBookClientView *client_view = NULL;
364 EAddressbookModel *model = user_data;
365 GError *error = NULL;
366
367 if (!e_book_client_get_view_finish (book_client, result, &client_view, &error))
368 client_view = NULL;
369
370 if (error) {
371 eab_error_dialog (NULL, _("Error getting book view"), error);
372 g_error_free (error);
373 return;
374 }
375
376 remove_book_view (model);
377 free_data (model);
378
379 model->priv->client_view = client_view;
380 if (model->priv->client_view) {
381 model->priv->create_contact_id = g_signal_connect (
382 model->priv->client_view, "objects-added",
383 G_CALLBACK (view_create_contact_cb), model);
384 model->priv->remove_contact_id = g_signal_connect (
385 model->priv->client_view, "objects-removed",
386 G_CALLBACK (view_remove_contact_cb), model);
387 model->priv->modify_contact_id = g_signal_connect (
388 model->priv->client_view, "objects-modified",
389 G_CALLBACK (view_modify_contact_cb), model);
390 model->priv->status_message_id = g_signal_connect (
391 model->priv->client_view, "progress",
392 G_CALLBACK (view_progress_cb), model);
393 model->priv->view_complete_id = g_signal_connect (
394 model->priv->client_view, "complete",
395 G_CALLBACK (view_complete_cb), model);
396
397 model->priv->search_in_progress = TRUE;
398 }
399
400 g_signal_emit (model, signals[MODEL_CHANGED], 0);
401 g_signal_emit (model, signals[SEARCH_STARTED], 0);
402 g_signal_emit (model, signals[STOP_STATE_CHANGED], 0);
403
404 if (model->priv->client_view) {
405 e_book_client_view_start (model->priv->client_view, &error);
406
407 if (error != NULL) {
408 g_warning (
409 "%s: Failed to start client view: %s",
410 G_STRFUNC, error->message);
411 g_error_free (error);
412 }
413 }
414 }
415
416 static gboolean
417 addressbook_model_idle_cb (EAddressbookModel *model)
418 {
419 model->priv->client_view_idle_id = 0;
420
421 if (model->priv->book_client && model->priv->query_str) {
422 remove_book_view (model);
423
424 if (model->priv->first_get_view) {
425 model->priv->first_get_view = FALSE;
426
427 if (e_client_check_capability (E_CLIENT (model->priv->book_client), "do-initial-query")) {
428 e_book_client_get_view (
429 model->priv->book_client, model->priv->query_str,
430 NULL, client_view_ready_cb, model);
431 } else {
432 free_data (model);
433
434 g_signal_emit (
435 model, signals[MODEL_CHANGED], 0);
436 g_signal_emit (
437 model, signals[STOP_STATE_CHANGED], 0);
438 }
439 } else
440 e_book_client_get_view (
441 model->priv->book_client, model->priv->query_str,
442 NULL, client_view_ready_cb, model);
443
444 }
445
446 g_object_unref (model);
447
448 return FALSE;
449 }
450
451 static gboolean
452 remove_status_cb (gpointer data)
453 {
454 EAddressbookModel *model = data;
455
456 g_return_val_if_fail (model != NULL, FALSE);
457 g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), FALSE);
458
459 g_signal_emit (model, signals[STATUS_MESSAGE], 0, NULL, -1);
460 model->priv->remove_status_id = 0;
461
462 return FALSE;
463 }
464
465 static void
466 addressbook_model_set_registry (EAddressbookModel *model,
467 ESourceRegistry *registry)
468 {
469 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
470 g_return_if_fail (model->priv->registry == NULL);
471
472 model->priv->registry = g_object_ref (registry);
473 }
474
475 static void
476 addressbook_model_set_property (GObject *object,
477 guint property_id,
478 const GValue *value,
479 GParamSpec *pspec)
480 {
481 switch (property_id) {
482 case PROP_CLIENT:
483 e_addressbook_model_set_client (
484 E_ADDRESSBOOK_MODEL (object),
485 g_value_get_object (value));
486 return;
487
488 case PROP_EDITABLE:
489 e_addressbook_model_set_editable (
490 E_ADDRESSBOOK_MODEL (object),
491 g_value_get_boolean (value));
492 return;
493
494 case PROP_QUERY:
495 e_addressbook_model_set_query (
496 E_ADDRESSBOOK_MODEL (object),
497 g_value_get_string (value));
498 return;
499
500 case PROP_REGISTRY:
501 addressbook_model_set_registry (
502 E_ADDRESSBOOK_MODEL (object),
503 g_value_get_object (value));
504 return;
505 }
506
507 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
508
509 }
510
511 static void
512 addressbook_model_get_property (GObject *object,
513 guint property_id,
514 GValue *value,
515 GParamSpec *pspec)
516 {
517 switch (property_id) {
518 case PROP_CLIENT:
519 g_value_set_object (
520 value, e_addressbook_model_get_client (
521 E_ADDRESSBOOK_MODEL (object)));
522 return;
523
524 case PROP_EDITABLE:
525 g_value_set_boolean (
526 value, e_addressbook_model_get_editable (
527 E_ADDRESSBOOK_MODEL (object)));
528 return;
529
530 case PROP_QUERY:
531 g_value_set_string (
532 value, e_addressbook_model_get_query (
533 E_ADDRESSBOOK_MODEL (object)));
534 return;
535
536 case PROP_REGISTRY:
537 g_value_set_object (
538 value, e_addressbook_model_get_registry (
539 E_ADDRESSBOOK_MODEL (object)));
540 return;
541 }
542
543 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
544 }
545
546 static void
547 addressbook_model_dispose (GObject *object)
548 {
549 EAddressbookModel *model = E_ADDRESSBOOK_MODEL (object);
550
551 remove_book_view (model);
552 free_data (model);
553
554 if (model->priv->book_client) {
555 if (model->priv->writable_status_id)
556 g_signal_handler_disconnect (
557 model->priv->book_client,
558 model->priv->writable_status_id);
559 model->priv->writable_status_id = 0;
560
561 if (model->priv->backend_died_id)
562 g_signal_handler_disconnect (
563 model->priv->book_client,
564 model->priv->backend_died_id);
565 model->priv->backend_died_id = 0;
566
567 g_object_unref (model->priv->book_client);
568 model->priv->book_client = NULL;
569 }
570
571 if (model->priv->query_str) {
572 g_free (model->priv->query_str);
573 model->priv->query_str = NULL;
574 }
575
576 /* Chain up to parent's dispose() method. */
577 G_OBJECT_CLASS (e_addressbook_model_parent_class)->dispose (object);
578 }
579
580 static void
581 addressbook_model_finalize (GObject *object)
582 {
583 EAddressbookModelPrivate *priv;
584
585 priv = E_ADDRESSBOOK_MODEL_GET_PRIVATE (object);
586
587 g_ptr_array_free (priv->contacts, TRUE);
588
589 /* Chain up to parent's finalize() method. */
590 G_OBJECT_CLASS (e_addressbook_model_parent_class)->finalize (object);
591 }
592
593 static void
594 e_addressbook_model_class_init (EAddressbookModelClass *class)
595 {
596 GObjectClass *object_class;
597
598 g_type_class_add_private (class, sizeof (EAddressbookModelPrivate));
599
600 object_class = G_OBJECT_CLASS (class);
601 object_class->set_property = addressbook_model_set_property;
602 object_class->get_property = addressbook_model_get_property;
603 object_class->dispose = addressbook_model_dispose;
604 object_class->finalize = addressbook_model_finalize;
605
606 g_object_class_install_property (
607 object_class,
608 PROP_CLIENT,
609 g_param_spec_object (
610 "client",
611 "EBookClient",
612 NULL,
613 E_TYPE_BOOK_CLIENT,
614 G_PARAM_READWRITE |
615 G_PARAM_STATIC_STRINGS));
616
617 g_object_class_install_property (
618 object_class,
619 PROP_EDITABLE,
620 g_param_spec_boolean (
621 "editable",
622 "Editable",
623 NULL,
624 FALSE,
625 G_PARAM_READWRITE |
626 G_PARAM_STATIC_STRINGS));
627
628 g_object_class_install_property (
629 object_class,
630 PROP_QUERY,
631 g_param_spec_string (
632 "query",
633 "Query",
634 NULL,
635 NULL,
636 G_PARAM_READWRITE |
637 G_PARAM_CONSTRUCT |
638 G_PARAM_STATIC_STRINGS));
639
640 g_object_class_install_property (
641 object_class,
642 PROP_REGISTRY,
643 g_param_spec_object (
644 "registry",
645 "Registry",
646 "Data source registry",
647 E_TYPE_SOURCE_REGISTRY,
648 G_PARAM_READWRITE |
649 G_PARAM_CONSTRUCT_ONLY |
650 G_PARAM_STATIC_STRINGS));
651
652 signals[WRITABLE_STATUS] = g_signal_new (
653 "writable_status",
654 G_OBJECT_CLASS_TYPE (object_class),
655 G_SIGNAL_RUN_LAST,
656 G_STRUCT_OFFSET (EAddressbookModelClass, writable_status),
657 NULL, NULL,
658 g_cclosure_marshal_VOID__BOOLEAN,
659 G_TYPE_NONE, 1,
660 G_TYPE_BOOLEAN);
661
662 signals[STATUS_MESSAGE] = g_signal_new (
663 "status_message",
664 G_OBJECT_CLASS_TYPE (object_class),
665 G_SIGNAL_RUN_LAST,
666 G_STRUCT_OFFSET (EAddressbookModelClass, status_message),
667 NULL, NULL,
668 e_marshal_VOID__STRING_INT,
669 G_TYPE_NONE, 2,
670 G_TYPE_STRING,
671 G_TYPE_INT);
672
673 signals[SEARCH_STARTED] = g_signal_new (
674 "search_started",
675 G_OBJECT_CLASS_TYPE (object_class),
676 G_SIGNAL_RUN_LAST,
677 G_STRUCT_OFFSET (EAddressbookModelClass, search_started),
678 NULL, NULL,
679 g_cclosure_marshal_VOID__VOID,
680 G_TYPE_NONE, 0);
681
682 signals[SEARCH_RESULT] = g_signal_new (
683 "search_result",
684 G_OBJECT_CLASS_TYPE (object_class),
685 G_SIGNAL_RUN_LAST,
686 G_STRUCT_OFFSET (EAddressbookModelClass, search_result),
687 NULL, NULL,
688 g_cclosure_marshal_VOID__BOXED,
689 G_TYPE_NONE, 1,
690 G_TYPE_ERROR);
691
692 signals[FOLDER_BAR_MESSAGE] = g_signal_new (
693 "folder_bar_message",
694 G_OBJECT_CLASS_TYPE (object_class),
695 G_SIGNAL_RUN_LAST,
696 G_STRUCT_OFFSET (EAddressbookModelClass, folder_bar_message),
697 NULL, NULL,
698 g_cclosure_marshal_VOID__POINTER,
699 G_TYPE_NONE, 1,
700 G_TYPE_POINTER);
701
702 signals[CONTACT_ADDED] = g_signal_new (
703 "contact_added",
704 G_OBJECT_CLASS_TYPE (object_class),
705 G_SIGNAL_RUN_LAST,
706 G_STRUCT_OFFSET (EAddressbookModelClass, contact_added),
707 NULL, NULL,
708 e_marshal_NONE__INT_INT,
709 G_TYPE_NONE, 2,
710 G_TYPE_INT,
711 G_TYPE_INT);
712
713 signals[CONTACTS_REMOVED] = g_signal_new (
714 "contacts_removed",
715 G_OBJECT_CLASS_TYPE (object_class),
716 G_SIGNAL_RUN_LAST,
717 G_STRUCT_OFFSET (EAddressbookModelClass, contacts_removed),
718 NULL, NULL,
719 g_cclosure_marshal_VOID__POINTER,
720 G_TYPE_NONE, 1,
721 G_TYPE_POINTER);
722
723 signals[CONTACT_CHANGED] = g_signal_new (
724 "contact_changed",
725 G_OBJECT_CLASS_TYPE (object_class),
726 G_SIGNAL_RUN_LAST,
727 G_STRUCT_OFFSET (EAddressbookModelClass, contact_changed),
728 NULL, NULL,
729 g_cclosure_marshal_VOID__INT,
730 G_TYPE_NONE, 1,
731 G_TYPE_INT);
732
733 signals[MODEL_CHANGED] = g_signal_new (
734 "model_changed",
735 G_OBJECT_CLASS_TYPE (object_class),
736 G_SIGNAL_RUN_LAST,
737 G_STRUCT_OFFSET (EAddressbookModelClass, model_changed),
738 NULL, NULL,
739 g_cclosure_marshal_VOID__VOID,
740 G_TYPE_NONE, 0);
741
742 signals[STOP_STATE_CHANGED] = g_signal_new (
743 "stop_state_changed",
744 G_OBJECT_CLASS_TYPE (object_class),
745 G_SIGNAL_RUN_LAST,
746 G_STRUCT_OFFSET (EAddressbookModelClass, stop_state_changed),
747 NULL, NULL,
748 g_cclosure_marshal_VOID__VOID,
749 G_TYPE_NONE, 0);
750
751 signals[BACKEND_DIED] = g_signal_new (
752 "backend_died",
753 G_OBJECT_CLASS_TYPE (object_class),
754 G_SIGNAL_RUN_LAST,
755 G_STRUCT_OFFSET (EAddressbookModelClass, backend_died),
756 NULL, NULL,
757 g_cclosure_marshal_VOID__VOID,
758 G_TYPE_NONE, 0);
759 }
760
761 static void
762 e_addressbook_model_init (EAddressbookModel *model)
763 {
764 model->priv = E_ADDRESSBOOK_MODEL_GET_PRIVATE (model);
765 model->priv->contacts = g_ptr_array_new ();
766 model->priv->first_get_view = TRUE;
767 }
768
769 EAddressbookModel *
770 e_addressbook_model_new (ESourceRegistry *registry)
771 {
772 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
773
774 return g_object_new (
775 E_TYPE_ADDRESSBOOK_MODEL,
776 "registry", registry, NULL);
777 }
778
779 ESourceRegistry *
780 e_addressbook_model_get_registry (EAddressbookModel *model)
781 {
782 g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL);
783
784 return model->priv->registry;
785 }
786
787 EContact *
788 e_addressbook_model_get_contact (EAddressbookModel *model,
789 gint row)
790 {
791 GPtrArray *array;
792
793 g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL);
794
795 array = model->priv->contacts;
796
797 if (0 <= row && row < array->len)
798 return e_contact_duplicate (array->pdata[row]);
799
800 return NULL;
801 }
802
803 void
804 e_addressbook_model_stop (EAddressbookModel *model)
805 {
806 const gchar *message;
807
808 g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model));
809
810 remove_book_view (model);
811
812 message = _("Search Interrupted");
813 g_signal_emit (model, signals[STOP_STATE_CHANGED], 0);
814 g_signal_emit (model, signals[STATUS_MESSAGE], 0, message, -1);
815
816 if (!model->priv->remove_status_id)
817 model->priv->remove_status_id =
818 g_timeout_add_seconds (3, remove_status_cb, model);
819 }
820
821 gboolean
822 e_addressbook_model_can_stop (EAddressbookModel *model)
823 {
824 g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), FALSE);
825
826 return model->priv->search_in_progress;
827 }
828
829 void
830 e_addressbook_model_force_folder_bar_message (EAddressbookModel *model)
831 {
832 g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model));
833
834 update_folder_bar_message (model);
835 }
836
837 gint
838 e_addressbook_model_contact_count (EAddressbookModel *model)
839 {
840 g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), 0);
841
842 return model->priv->contacts->len;
843 }
844
845 EContact *
846 e_addressbook_model_contact_at (EAddressbookModel *model,
847 gint index)
848 {
849 g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL);
850
851 return model->priv->contacts->pdata[index];
852 }
853
854 gint
855 e_addressbook_model_find (EAddressbookModel *model,
856 EContact *contact)
857 {
858 GPtrArray *array;
859 gint ii;
860
861 /* XXX This searches for a particular EContact instance,
862 * as opposed to an equivalent but possibly different
863 * EContact instance. Might have to revise this in
864 * the future. */
865
866 g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), -1);
867 g_return_val_if_fail (E_IS_CONTACT (contact), -1);
868
869 array = model->priv->contacts;
870 for (ii = 0; ii < array->len; ii++) {
871 EContact *candidate = array->pdata[ii];
872
873 if (contact == candidate)
874 return ii;
875 }
876
877 return -1;
878 }
879
880 EBookClient *
881 e_addressbook_model_get_client (EAddressbookModel *model)
882 {
883 g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL);
884
885 return model->priv->book_client;
886 }
887
888 void
889 e_addressbook_model_set_client (EAddressbookModel *model,
890 EBookClient *book_client)
891 {
892 gboolean editable;
893
894 g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model));
895 g_return_if_fail (E_IS_BOOK_CLIENT (book_client));
896
897 if (model->priv->book_client == book_client)
898 return;
899
900 if (model->priv->book_client != NULL) {
901 if (model->priv->book_client == book_client)
902 return;
903
904 if (model->priv->writable_status_id != 0)
905 g_signal_handler_disconnect (
906 model->priv->book_client,
907 model->priv->writable_status_id);
908 model->priv->writable_status_id = 0;
909
910 if (model->priv->backend_died_id != 0)
911 g_signal_handler_disconnect (
912 model->priv->book_client,
913 model->priv->backend_died_id);
914 model->priv->backend_died_id = 0;
915
916 g_object_unref (model->priv->book_client);
917 }
918
919 model->priv->book_client = g_object_ref (book_client);
920 model->priv->first_get_view = TRUE;
921
922 model->priv->writable_status_id = g_signal_connect (
923 book_client, "notify::readonly",
924 G_CALLBACK (readonly_cb), model);
925
926 model->priv->backend_died_id = g_signal_connect (
927 book_client, "backend-died",
928 G_CALLBACK (backend_died_cb), model);
929
930 editable = !e_client_is_readonly (E_CLIENT (book_client));
931 e_addressbook_model_set_editable (model, editable);
932
933 if (model->priv->client_view_idle_id == 0)
934 model->priv->client_view_idle_id = g_idle_add (
935 (GSourceFunc) addressbook_model_idle_cb,
936 g_object_ref (model));
937
938 g_object_notify (G_OBJECT (model), "client");
939 }
940
941 gboolean
942 e_addressbook_model_get_editable (EAddressbookModel *model)
943 {
944 g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), FALSE);
945
946 return model->priv->editable;
947 }
948
949 void
950 e_addressbook_model_set_editable (EAddressbookModel *model,
951 gboolean editable)
952 {
953 g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model));
954
955 if (model->priv->editable != editable) {
956 model->priv->editable = editable;
957
958 g_signal_emit (
959 model, signals[WRITABLE_STATUS], 0,
960 model->priv->editable);
961
962 g_object_notify (G_OBJECT (model), "editable");
963 }
964 }
965
966 gchar *
967 e_addressbook_model_get_query (EAddressbookModel *model)
968 {
969 g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL);
970
971 return model->priv->query_str;
972 }
973
974 void
975 e_addressbook_model_set_query (EAddressbookModel *model,
976 const gchar *query)
977 {
978 EBookQuery *book_query;
979
980 g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model));
981
982 if (query == NULL)
983 book_query = e_book_query_any_field_contains ("");
984 else
985 book_query = e_book_query_from_string (query);
986
987 /* also checks whether the query is a valid query string */
988 if (!book_query)
989 return;
990
991 if (model->priv->query_str != NULL) {
992 gchar *new_query;
993
994 new_query = e_book_query_to_string (book_query);
995
996 if (new_query && g_str_equal (model->priv->query_str, new_query)) {
997 g_free (new_query);
998 e_book_query_unref (book_query);
999 return;
1000 }
1001
1002 g_free (new_query);
1003 }
1004
1005 g_free (model->priv->query_str);
1006 model->priv->query_str = e_book_query_to_string (book_query);
1007 e_book_query_unref (book_query);
1008
1009 if (model->priv->client_view_idle_id == 0)
1010 model->priv->client_view_idle_id = g_idle_add (
1011 (GSourceFunc) addressbook_model_idle_cb,
1012 g_object_ref (model));
1013
1014 g_object_notify (G_OBJECT (model), "query");
1015 }