]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-individual-manager.c
Merge branch 'folks-async-and-prepare'
[empathy.git] / libempathy / empathy-individual-manager.c
index 53843ce93d7702f223beef4c5976504dff09efa6..55541b29955a7c9e997acd2bdaacf47346d0ef3f 100644 (file)
 #include "empathy-debug.h"
 
 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIndividualManager)
+
+/* This class doesn't store or ref any of the individuals, since they're already
+ * stored and referenced in the aggregator.
+ *
+ * This class merely forwards along signals from the aggregator and individuals
+ * and wraps aggregator functions for other client code. */
 typedef struct
 {
   FolksIndividualAggregator *aggregator;
   EmpathyContactManager *contact_manager;
-  TpProxy *logger;
 } EmpathyIndividualManagerPriv;
 
+enum
+{
+  FAVOURITES_CHANGED,
+  GROUPS_CHANGED,
+  MEMBERS_CHANGED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 G_DEFINE_TYPE (EmpathyIndividualManager, empathy_individual_manager,
     G_TYPE_OBJECT);
 
@@ -61,61 +76,63 @@ individual_group_changed_cb (FolksIndividual *individual,
     gboolean is_member,
     EmpathyIndividualManager *self)
 {
-  g_signal_emit_by_name (self, "groups-changed", individual, group,
+  g_signal_emit (self, signals[GROUPS_CHANGED], 0, individual, group,
       is_member);
 }
 
 static void
-aggregator_individuals_added_cb (FolksIndividualAggregator *aggregator,
-    GList *individuals,
+individual_notify_is_favourite_cb (FolksIndividual *individual,
+    GParamSpec *pspec,
     EmpathyIndividualManager *self)
 {
-  GList *l;
-
-  for (l = individuals; l; l = l->next)
-    {
-      g_signal_connect (l->data, "group-changed",
-          G_CALLBACK (individual_group_changed_cb), self);
-    }
-
-  /* TODO: don't hard-code the reason or message */
-  g_signal_emit_by_name (self, "members-changed",
-      "individual(s) added", individuals, NULL,
-      TP_CHANNEL_GROUP_CHANGE_REASON_NONE, TRUE);
+  gboolean is_favourite = folks_favourite_get_is_favourite (
+      FOLKS_FAVOURITE (individual));
+  g_signal_emit (self, signals[FAVOURITES_CHANGED], 0, individual,
+      is_favourite);
 }
 
 static void
-aggregator_individuals_removed_cb (FolksIndividualAggregator *aggregator,
-    GList *individuals,
+aggregator_individuals_changed_cb (FolksIndividualAggregator *aggregator,
+    GList *added,
+    GList *removed,
+    const char *message,
+    FolksPersona *actor,
+    guint reason,
     EmpathyIndividualManager *self)
 {
   GList *l;
 
-  for (l = individuals; l; l = l->next)
+  for (l = added; l; l = l->next)
+    {
+      g_signal_connect (l->data, "group-changed",
+          G_CALLBACK (individual_group_changed_cb), self);
+      g_signal_connect (l->data, "notify::is-favourite",
+          G_CALLBACK (individual_notify_is_favourite_cb), self);
+    }
+
+  for (l = removed; l; l = l->next)
     {
       g_signal_handlers_disconnect_by_func (l->data,
           individual_group_changed_cb, self);
+      g_signal_handlers_disconnect_by_func (l->data,
+          individual_notify_is_favourite_cb, self);
     }
 
-  /* TODO: don't hard-code the reason or message */
-  g_signal_emit_by_name (self, "members-changed",
-      "individual(s) removed", NULL, individuals,
-      TP_CHANNEL_GROUP_CHANGE_REASON_NONE, TRUE);
+  g_signal_emit (self, signals[MEMBERS_CHANGED], 0, message,
+      added, removed,
+      tp_chanel_group_change_reason_from_folks_groups_change_reason (reason),
+      TRUE);
 }
 
 static void
-individual_manager_finalize (GObject *object)
+individual_manager_dispose (GObject *object)
 {
   EmpathyIndividualManagerPriv *priv = GET_PRIV (object);
 
-  if (priv->logger != NULL)
-    g_object_unref (priv->logger);
-
-  if (priv->contact_manager != NULL)
-    g_object_unref (priv->contact_manager);
+  tp_clear_object (&priv->contact_manager);
+  tp_clear_object (&priv->aggregator);
 
-  if (priv->aggregator != NULL)
-    g_object_unref (priv->aggregator);
+  G_OBJECT_CLASS (empathy_individual_manager_parent_class)->dispose (object);
 }
 
 static GObject *
@@ -164,25 +181,36 @@ empathy_individual_manager_class_init (EmpathyIndividualManagerClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  object_class->finalize = individual_manager_finalize;
+  object_class->dispose = individual_manager_dispose;
   object_class->constructor = individual_manager_constructor;
 
-  g_signal_new ("groups-changed",
-      G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST,
-      0,
-      NULL, NULL,
-      _empathy_marshal_VOID__OBJECT_STRING_BOOLEAN,
-      G_TYPE_NONE, 3, FOLKS_TYPE_INDIVIDUAL, G_TYPE_STRING, G_TYPE_BOOLEAN);
-
-  g_signal_new ("members-changed",
-      G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST,
-      0,
-      NULL, NULL,
-      _empathy_marshal_VOID__STRING_OBJECT_OBJECT_UINT,
-      G_TYPE_NONE,
-      4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_UINT);
+  signals[GROUPS_CHANGED] =
+      g_signal_new ("groups-changed",
+          G_TYPE_FROM_CLASS (klass),
+          G_SIGNAL_RUN_LAST,
+          0,
+          NULL, NULL,
+          _empathy_marshal_VOID__OBJECT_STRING_BOOLEAN,
+          G_TYPE_NONE, 3, FOLKS_TYPE_INDIVIDUAL, G_TYPE_STRING, G_TYPE_BOOLEAN);
+
+  signals[FAVOURITES_CHANGED] =
+      g_signal_new ("favourites-changed",
+          G_TYPE_FROM_CLASS (klass),
+          G_SIGNAL_RUN_LAST,
+          0,
+          NULL, NULL,
+          _empathy_marshal_VOID__OBJECT_BOOLEAN,
+          G_TYPE_NONE, 2, FOLKS_TYPE_INDIVIDUAL, G_TYPE_BOOLEAN);
+
+  signals[MEMBERS_CHANGED] =
+      g_signal_new ("members-changed",
+          G_TYPE_FROM_CLASS (klass),
+          G_SIGNAL_RUN_LAST,
+          0,
+          NULL, NULL,
+          _empathy_marshal_VOID__STRING_OBJECT_OBJECT_UINT,
+          G_TYPE_NONE,
+          4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_UINT);
 
   g_type_class_add_private (object_class,
       sizeof (EmpathyIndividualManagerPriv));
@@ -193,35 +221,14 @@ empathy_individual_manager_init (EmpathyIndividualManager *self)
 {
   EmpathyIndividualManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
       EMPATHY_TYPE_INDIVIDUAL_MANAGER, EmpathyIndividualManagerPriv);
-  TpDBusDaemon *bus;
-  GError *error = NULL;
 
   self->priv = priv;
   priv->contact_manager = empathy_contact_manager_dup_singleton ();
 
   priv->aggregator = folks_individual_aggregator_new ();
-  g_signal_connect (priv->aggregator, "individuals-added",
-      G_CALLBACK (aggregator_individuals_added_cb), self);
-  g_signal_connect (priv->aggregator, "individuals-removed",
-      G_CALLBACK (aggregator_individuals_removed_cb), self);
-
-  bus = tp_dbus_daemon_dup (&error);
-
-  if (error == NULL)
-    {
-      priv->logger = g_object_new (TP_TYPE_PROXY,
-          "bus-name", "org.freedesktop.Telepathy.Logger",
-          "object-path",
-          "/org/freedesktop/Telepathy/Logger", "dbus-daemon", bus, NULL);
-      g_object_unref (bus);
-
-      tp_proxy_add_interface_by_id (priv->logger, EMP_IFACE_QUARK_LOGGER);
-    }
-  else
-    {
-      DEBUG ("Failed to get telepathy-logger proxy: %s", error->message);
-      g_clear_error (&error);
-    }
+  g_signal_connect (priv->aggregator, "individuals-changed",
+      G_CALLBACK (aggregator_individuals_changed_cb), self);
+  folks_individual_aggregator_prepare (priv->aggregator, NULL, NULL);
 }
 
 EmpathyIndividualManager *
@@ -230,8 +237,6 @@ empathy_individual_manager_dup_singleton (void)
   return g_object_new (EMPATHY_TYPE_INDIVIDUAL_MANAGER, NULL);
 }
 
-/* TODO: support adding and removing Individuals */
-
 GList *
 empathy_individual_manager_get_members (EmpathyIndividualManager *self)
 {
@@ -265,18 +270,25 @@ aggregator_add_persona_from_details_cb (GObject *source,
     GAsyncResult *result,
     gpointer user_data)
 {
-  EmpathyIndividualManager *self = EMPATHY_INDIVIDUAL_MANAGER (user_data);
-  EmpathyIndividualManagerPriv *priv = GET_PRIV (self);
+  FolksIndividualAggregator *aggregator = FOLKS_INDIVIDUAL_AGGREGATOR (source);
+  EmpathyContact *contact = EMPATHY_CONTACT (user_data);
   FolksPersona *persona;
   GError *error = NULL;
 
   persona = folks_individual_aggregator_add_persona_from_details_finish (
-      priv->aggregator, result, &error);
+      aggregator, result, &error);
   if (error != NULL)
     {
       g_warning ("failed to add individual from contact: %s", error->message);
       g_clear_error (&error);
     }
+
+  /* Set the contact's persona */
+  empathy_contact_set_persona (contact, persona);
+
+  /* We can unref the contact now */
+  g_object_unref (contact);
+  g_object_unref (persona);
 }
 
 void
@@ -293,23 +305,44 @@ empathy_individual_manager_add_from_contact (EmpathyIndividualManager *self,
 
   priv = GET_PRIV (self);
 
-  DEBUG (G_STRLOC ": adding individual from contact %s (%s)",
-      empathy_contact_get_id (contact), empathy_contact_get_name (contact));
+  /* We need to ref the contact since otherwise its linked TpHandle will be
+   * destroyed. */
+  g_object_ref (contact);
+
+  DEBUG ("adding individual from contact %s (%s)",
+      empathy_contact_get_id (contact), empathy_contact_get_alias (contact));
 
   account = empathy_contact_get_account (contact);
   store_id = tp_proxy_get_object_path (TP_PROXY (account));
 
-  details = g_hash_table_new (g_str_hash, g_str_equal);
-  g_hash_table_insert (details, "contact",
-      (gchar*) empathy_contact_get_id (contact));
+  details = tp_asv_new (
+      "contact", G_TYPE_STRING, empathy_contact_get_id (contact),
+      NULL);
 
   folks_individual_aggregator_add_persona_from_details (
       priv->aggregator, NULL, "telepathy", store_id, details,
-      aggregator_add_persona_from_details_cb, self);
+      aggregator_add_persona_from_details_cb, contact);
 
   g_hash_table_destroy (details);
 }
 
+static void
+aggregator_remove_individual_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  FolksIndividualAggregator *aggregator = FOLKS_INDIVIDUAL_AGGREGATOR (source);
+  GError *error = NULL;
+
+  folks_individual_aggregator_remove_individual_finish (
+      aggregator, result, &error);
+  if (error != NULL)
+    {
+      g_warning ("failed to remove individual: %s", error->message);
+      g_clear_error (&error);
+    }
+}
+
 /**
  * Removes the inner contact from the server (and thus the Individual). Not
  * meant for de-shelling inner personas from an Individual.
@@ -326,11 +359,57 @@ empathy_individual_manager_remove (EmpathyIndividualManager *self,
 
   priv = GET_PRIV (self);
 
-  DEBUG (G_STRLOC ": removing individual %s (%s)",
+  DEBUG ("removing individual %s (%s)",
       folks_individual_get_id (individual),
       folks_individual_get_alias (individual));
 
-  folks_individual_aggregator_remove_individual (priv->aggregator, individual);
+  folks_individual_aggregator_remove_individual (priv->aggregator, individual,
+      aggregator_remove_individual_cb, self);
+}
+
+static void
+groups_change_group_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  FolksGroups *groups = FOLKS_GROUPS (source);
+  GError *error = NULL;
+
+  folks_groups_change_group_finish (groups, result, &error);
+  if (error != NULL)
+    {
+      g_warning ("failed to change group: %s", error->message);
+      g_clear_error (&error);
+    }
+}
+
+static void
+remove_group_cb (const gchar *id,
+    FolksIndividual *individual,
+    const gchar *group)
+{
+  folks_groups_change_group (FOLKS_GROUPS (individual), group, FALSE,
+      groups_change_group_cb, NULL);
+}
+
+void
+empathy_individual_manager_remove_group (EmpathyIndividualManager *manager,
+    const gchar *group)
+{
+  EmpathyIndividualManagerPriv *priv;
+  GHashTable *individuals;
+
+  g_return_if_fail (EMPATHY_IS_INDIVIDUAL_MANAGER (manager));
+  g_return_if_fail (group != NULL);
+
+  priv = GET_PRIV (manager);
+
+  DEBUG ("removing group %s", group);
+
+  /* Remove every individual from the group */
+  individuals = folks_individual_aggregator_get_individuals (priv->aggregator);
+  g_hash_table_foreach (individuals, (GHFunc) remove_group_cb,
+      (gpointer) group);
 }
 
 EmpathyIndividualManagerFlags