contacts: load new contacts when they're added

Connect to the EBookClientView to be able to react to
changes in the addressbook.

This patch reacts to contacts being added. Later patches
will react to contacts being removed and modified.

Refs #73494

Change-Id: I939ee48103caa07c87e3be957ea42c1ba95c9cc7
diff --git a/src/backends/edscontactbackend.cpp b/src/backends/edscontactbackend.cpp
index e4b02dd..0fb502d 100644
--- a/src/backends/edscontactbackend.cpp
+++ b/src/backends/edscontactbackend.cpp
@@ -153,12 +153,29 @@
     return items_;
 }
 
+static void free_client_view(EBookClientView *client_view) {
+    g_return_if_fail(client_view);
+    GError *error = NULL;
+    e_book_client_view_stop(client_view, &error);
+    if (error) {
+        g_warning("error stopping EBookClientView: %s", error->message);
+        g_clear_error(&error);
+    }
+    g_object_unref(client_view);
+}
+
+static void
+free_contact_list(GSList *list)
+{
+    g_slist_free_full(list, g_object_unref);
+};
+
 EdsContactBackend::EdsContactBackend(CollectionMediator<Person>* mediator, EClient *client, CollectionInterface* parent)
     : CollectionInterface(new EdsContactEditor(mediator,this), parent)
     , mediator_(mediator)
     , client_(client, g_object_unref)
     , cancellable_(g_cancellable_new(), g_object_unref)
-    , contacts_(nullptr, free_contact_list)
+    , client_view_(nullptr, &free_client_view)
 {
 }
 
@@ -188,17 +205,28 @@
 }
 
 static void
-contacts_cb(EBookClient *client, GAsyncResult *result, EdsContactBackend *self)
+contacts_added(G_GNUC_UNUSED EBookClientView *client_view, const GSList *objects, EdsContactBackend *self)
+{
+    std::unique_ptr<GSList,void(*)(GSList *)> contacts(
+        g_slist_copy_deep((GSList *)objects, (GCopyFunc)g_object_ref, NULL ), &free_contact_list);
+    self->addContacts(std::move(contacts));
+}
+
+static void
+client_view_cb(EBookClient *client, GAsyncResult *result, EdsContactBackend *self)
 {
     g_return_if_fail(E_IS_BOOK_CLIENT(client));
-    GSList *contacts = NULL;
+    EBookClientView *client_view = NULL;
     GError *error = NULL;
-    if(!e_book_client_get_contacts_finish(client, result, &contacts, &error)) {
-        g_critical("Unable to get contacts: %s", error->message);
+    if(!e_book_client_get_view_finish(client, result, &client_view, &error)) {
+        g_critical("Unable to get client view: %s", error->message);
         g_clear_error(&error);
         return;
     } else {
-        self->addContacts(contacts);
+        /* we want the EBookClientView to have the same life cycle as the backend */
+        std::unique_ptr<EBookClientView, void(*)(EBookClientView *)> client_view_ptr(
+            client_view, &free_client_view);
+        self->addClientView(std::move(client_view_ptr));
     }
 }
 
@@ -231,8 +259,17 @@
 {
     EdsContactBackend* backend;
     GSList *next;
+    std::unique_ptr<GSList, void(*)(GSList *)> contacts;
 } AddContactsData;
 
+void
+free_add_contacts_data(AddContactsData *data)
+{
+    g_return_if_fail(data && data->contacts);
+    data->contacts.reset();
+    g_free(data);
+}
+
 static gboolean
 add_contacts(AddContactsData *data)
 {
@@ -256,21 +293,35 @@
     add_contacts_source_id = 0;
 }
 
-
-void EdsContactBackend::addContacts(GSList *contacts)
+void EdsContactBackend::addClientView(std::unique_ptr<EBookClientView, void(*)(EBookClientView *)> client_view)
 {
-    contacts_.reset(contacts);
+    client_view_ = std::move(client_view);
 
+    /* connect signals for adding, removing, and modifying contacts */
+    g_signal_connect(client_view_.get(), "objects-added", G_CALLBACK(contacts_added), this);
+
+    /* start processing the signals */
+    GError *error = NULL;
+    e_book_client_view_start(client_view_.get(), &error);
+    if (error) {
+        g_critical("Unable to get start client view: %s", error->message);
+        g_clear_error(&error);
+    }
+}
+
+void EdsContactBackend::addContacts(std::unique_ptr<GSList, void(*)(GSList *)> contacts)
+{
     /* add CONTACT_ADD_LIMIT # of contacts every CONTACT_ADD_INTERVAL miliseconds */
     AddContactsData *data = g_new0(AddContactsData, 1);
     data->backend = this;
-    data->next = contacts_.get();
+    data->contacts = std::move(contacts);
+    data->next = data->contacts.get();
 
     g_timeout_add_full(G_PRIORITY_DEFAULT,
                        CONTACT_ADD_INTERVAL,
                        (GSourceFunc)add_contacts,
                        data,
-                       (GDestroyNotify)g_free);
+                       (GDestroyNotify)free_add_contacts_data);
 }
 
 bool EdsContactBackend::load()
@@ -289,11 +340,13 @@
     EBookQuery *name_query = e_book_query_or(idx, queries, TRUE);
     gchar *query_str = e_book_query_to_string(name_query);
     e_book_query_unref(name_query);
-    e_book_client_get_contacts(E_BOOK_CLIENT(client_.get()),
-                               query_str,
-                               cancellable_.get(),
-                               (GAsyncReadyCallback)contacts_cb,
-                               this);
+
+    /* test */
+    e_book_client_get_view(E_BOOK_CLIENT(client_.get()),
+                           query_str,
+                           cancellable_.get(),
+                           (GAsyncReadyCallback)client_view_cb,
+                           this);
     g_free(query_str);
 
     return true;
diff --git a/src/backends/edscontactbackend.h b/src/backends/edscontactbackend.h
index 0bc9734..026676f 100644
--- a/src/backends/edscontactbackend.h
+++ b/src/backends/edscontactbackend.h
@@ -85,7 +85,8 @@
     virtual QByteArray id       () const override;
     virtual FlagPack<SupportedFeatures>  supportedFeatures() const override;
 
-    void addContacts(GSList *contacts);
+    void addClientView(std::unique_ptr<EBookClientView, void(*)(EBookClientView *)> client_view);
+    void addContacts(std::unique_ptr<GSList, void(*)(GSList *)> contacts);
     void parseContact(EContact *contact);
     void lastContactAdded();
 
@@ -93,11 +94,9 @@
    CollectionMediator<Person>*  mediator_;
    std::unique_ptr<EClient, decltype(g_object_unref)&> client_;
    std::unique_ptr<GCancellable, decltype(g_object_unref)&> cancellable_;
-
-   static void free_contact_list(GSList *list) { g_slist_free_full(list, g_object_unref); };
-   std::unique_ptr<GSList, decltype(free_contact_list)&> contacts_;
+   std::unique_ptr<EBookClientView, void(*)(EBookClientView *)> client_view_;
 
    guint add_contacts_source_id {0};
 };
 
-#endif /* EDSCONTACTBACKEND_H */
\ No newline at end of file
+#endif /* EDSCONTACTBACKEND_H */
diff --git a/src/callsview.cpp b/src/callsview.cpp
index 17873d9..6bc33a1 100644
--- a/src/callsview.cpp
+++ b/src/callsview.cpp
@@ -239,7 +239,7 @@
     priv->selection_updated = QObject::connect(
         CallModel::instance()->selectionModel(),
         &QItemSelectionModel::currentChanged,
-        [=](const QModelIndex & current, const QModelIndex & previous) {
+        [=](const QModelIndex current, const QModelIndex & previous) {
             GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_calls));
 
             /* first unselect the previous */
@@ -311,4 +311,4 @@
     CallsViewPrivate *priv = CALLS_VIEW_GET_PRIVATE(calls_view);
 
     return gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview_calls));
-}
\ No newline at end of file
+}