add EMPATHY_INDIVIDUAL_FEATURE_ADD_CONTACT
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Tue, 8 Nov 2011 13:06:49 +0000 (14:06 +0100)
committerGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Thu, 24 Nov 2011 11:28:44 +0000 (12:28 +0100)
https://bugzilla.gnome.org/show_bug.cgi?id=663387

libempathy-gtk/empathy-individual-menu.c
libempathy-gtk/empathy-individual-menu.h
libempathy-gtk/empathy-individual-view.c
libempathy/empathy-client-factory.c
src/empathy-main-window.c

index 27b2c67c2e27840cfc633d2bff6fc69c5b1e995f..607455f9b9ff9e024cf03b5f00d1eef41d45241a 100644 (file)
@@ -49,6 +49,7 @@
 #include "empathy-share-my-desktop.h"
 #include "empathy-linking-dialog.h"
 #include "empathy-call-utils.h"
+#include "empathy-individual-store-channel.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
 #include <libempathy/empathy-debug.h>
 typedef struct {
   FolksIndividual *individual; /* owned */
   EmpathyIndividualFeatureFlags features;
+  EmpathyIndividualStore *store;
 } EmpathyIndividualMenuPriv;
 
 enum {
   PROP_INDIVIDUAL = 1,
   PROP_FEATURES,
+  PROP_STORE,
 };
 
 enum {
@@ -454,6 +457,17 @@ constructed (GObject *object)
   individual = priv->individual;
   features = priv->features;
 
+  /* Add contact */
+  if (features & EMPATHY_INDIVIDUAL_FEATURE_ADD_CONTACT)
+    {
+      item = empathy_individual_add_menu_item_new (self, individual);
+      if (item != NULL)
+        {
+          gtk_menu_shell_append (GTK_MENU_SHELL (shell), item);
+          gtk_widget_show (item);
+        }
+    }
+
   /* Chat */
   if (features & EMPATHY_INDIVIDUAL_FEATURE_CHAT)
     {
@@ -586,6 +600,9 @@ get_property (GObject *object,
       case PROP_FEATURES:
         g_value_set_flags (value, priv->features);
         break;
+      case PROP_STORE:
+        g_value_set_object (value, priv->store);
+        break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
         break;
@@ -610,6 +627,9 @@ set_property (GObject *object,
       case PROP_FEATURES:
         priv->features = g_value_get_flags (value);
         break;
+      case PROP_STORE:
+        priv->store = g_value_dup_object (value); /* read only */
+        break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
         break;
@@ -622,6 +642,7 @@ dispose (GObject *object)
   EmpathyIndividualMenuPriv *priv = GET_PRIV (object);
 
   tp_clear_object (&priv->individual);
+  tp_clear_object (&priv->store);
 
   G_OBJECT_CLASS (empathy_individual_menu_parent_class)->dispose (object);
 }
@@ -661,6 +682,13 @@ empathy_individual_menu_class_init (EmpathyIndividualMenuClass *klass)
           EMPATHY_INDIVIDUAL_FEATURE_NONE,
           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (object_class, PROP_STORE,
+      g_param_spec_object ("store",
+          "Store",
+          "The EmpathyIndividualStore to use to get contact owner",
+          EMPATHY_TYPE_INDIVIDUAL_STORE,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
   signals[SIGNAL_LINK_CONTACTS_ACTIVATED] =
       g_signal_new ("link-contacts-activated", G_OBJECT_CLASS_TYPE (klass),
           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
@@ -672,14 +700,17 @@ empathy_individual_menu_class_init (EmpathyIndividualMenuClass *klass)
 
 GtkWidget *
 empathy_individual_menu_new (FolksIndividual *individual,
-    EmpathyIndividualFeatureFlags features)
+    EmpathyIndividualFeatureFlags features,
+    EmpathyIndividualStore *store)
 {
   g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
+  g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_STORE (store), NULL);
   g_return_val_if_fail (features != EMPATHY_INDIVIDUAL_FEATURE_NONE, NULL);
 
   return g_object_new (EMPATHY_TYPE_INDIVIDUAL_MENU,
       "individual", individual,
       "features", features,
+      "store", store,
       NULL);
 }
 
@@ -1427,3 +1458,110 @@ empathy_individual_invite_menu_item_new (FolksIndividual *individual,
 
   return item;
 }
+
+static void
+add_menu_item_activated (GtkMenuItem *item,
+    TpContact *tp_contact)
+{
+  GtkWidget *toplevel;
+  EmpathyContact *contact;
+
+  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item));
+  if (!gtk_widget_is_toplevel (toplevel) || !GTK_IS_WINDOW (toplevel))
+    toplevel = NULL;
+
+  contact = empathy_contact_dup_from_tp_contact (tp_contact);
+
+  empathy_new_contact_dialog_show_with_contact (GTK_WINDOW (toplevel),
+      contact);
+
+  g_object_unref (contact);
+}
+
+GtkWidget *
+empathy_individual_add_menu_item_new (EmpathyIndividualMenu *self,
+    FolksIndividual *individual)
+{
+  EmpathyIndividualMenuPriv *priv = GET_PRIV (self);
+  GtkWidget *item, *image;
+  GeeSet *personas;
+  GeeIterator *iter;
+  TpContact *to_add = NULL;
+
+  /* find the first of this Individual's personas which are not in our contact
+   * list. */
+  personas = folks_individual_get_personas (individual);
+  iter = gee_iterable_iterator (GEE_ITERABLE (personas));
+  while (gee_iterator_next (iter))
+    {
+      TpfPersona *persona = gee_iterator_get (iter);
+      TpContact *contact;
+      TpConnection *conn;
+
+      if (!TPF_IS_PERSONA (persona))
+        goto next;
+
+      contact = tpf_persona_get_contact (persona);
+      if (contact == NULL)
+        goto next;
+
+      /* be sure to use a not channel specific contact.
+       * TODO: Ideally tp-glib should do this for us (fdo #42702)*/
+      if (EMPATHY_IS_INDIVIDUAL_STORE_CHANNEL (priv->store))
+        {
+          TpChannel *channel;
+          TpChannelGroupFlags flags;
+
+          channel = empathy_individual_store_channel_get_channel (
+              EMPATHY_INDIVIDUAL_STORE_CHANNEL (priv->store));
+
+          flags = tp_channel_group_get_flags (channel);
+          if ((flags & TP_CHANNEL_GROUP_FLAG_CHANNEL_SPECIFIC_HANDLES) != 0)
+            {
+              /* Channel uses channel specific handles (thanks XMPP...) */
+              contact = tp_channel_group_get_contact_owner (channel, contact);
+
+              /* If we don't know the owner, we can't add the contact */
+              if (contact == NULL)
+                goto next;
+            }
+        }
+
+      conn = tp_contact_get_connection (contact);
+      if (conn == NULL)
+        goto next;
+
+      /* No point to try adding a contact if the CM doesn't support it */
+      if (!tp_connection_get_can_change_contact_list (conn))
+        goto next;
+
+      /* Can't add ourself */
+      if (tp_connection_get_self_contact (conn) == contact)
+        goto next;
+
+      if (tp_contact_get_subscribe_state (contact) == TP_SUBSCRIPTION_STATE_YES)
+        goto next;
+
+      g_object_unref (persona);
+      to_add = contact;
+      break;
+
+next:
+      g_object_unref (persona);
+    }
+
+  g_object_unref (iter);
+
+  if (to_add == NULL)
+    return NULL;
+
+  item = gtk_image_menu_item_new_with_mnemonic (_("_Add Contact…"));
+  image = gtk_image_new_from_icon_name (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+
+  g_signal_connect_data (item, "activate",
+      G_CALLBACK (add_menu_item_activated),
+      g_object_ref (to_add), (GClosureNotify) g_object_unref, 0);
+
+  return item;
+}
index 2a51605d6b02b48522245de5239812f2d0e6d70b..31acc156ee9f5314d9889646effe2257f9c6bedc 100644 (file)
@@ -25,6 +25,8 @@
 
 #include <gtk/gtk.h>
 
+#include "empathy-individual-store.h"
+
 G_BEGIN_DECLS
 
 typedef enum {
@@ -38,7 +40,8 @@ typedef enum {
        EMPATHY_INDIVIDUAL_FEATURE_LINK = 1 << 6,
        EMPATHY_INDIVIDUAL_FEATURE_SMS = 1 << 7,
        EMPATHY_INDIVIDUAL_FEATURE_CALL_PHONE = 1 << 8,
-       EMPATHY_INDIVIDUAL_FEATURE_ALL = (1 << 9) - 1,
+       EMPATHY_INDIVIDUAL_FEATURE_ADD_CONTACT = 1 << 9,
+       EMPATHY_INDIVIDUAL_FEATURE_ALL = (1 << 10) - 1,
 } EmpathyIndividualFeatureFlags;
 
 #define EMPATHY_TYPE_INDIVIDUAL_MENU (empathy_individual_menu_get_type ())
@@ -68,7 +71,8 @@ typedef struct {
 GType empathy_individual_menu_get_type (void) G_GNUC_CONST;
 
 GtkWidget * empathy_individual_menu_new (FolksIndividual *individual,
-    EmpathyIndividualFeatureFlags features);
+    EmpathyIndividualFeatureFlags features,
+    EmpathyIndividualStore *store);
 GtkWidget * empathy_individual_chat_menu_item_new (FolksIndividual *individual,
     EmpathyContact *contact);
 GtkWidget * empathy_individual_sms_menu_item_new (FolksIndividual *individual,
@@ -95,6 +99,8 @@ GtkWidget * empathy_individual_share_my_desktop_menu_item_new (
     EmpathyContact *contact);
 GtkWidget * empathy_individual_favourite_menu_item_new (
     FolksIndividual *individual);
+GtkWidget * empathy_individual_add_menu_item_new (EmpathyIndividualMenu *self,
+    FolksIndividual *individual);
 
 G_END_DECLS
 
index 3cd1500a8b496d3ff4fb4f0a4ca14fb4d637d1e2..64aaf5a0aec6f9d437a0ab4c6233cf939718d69c 100644 (file)
@@ -2650,7 +2650,8 @@ empathy_individual_view_get_individual_menu (EmpathyIndividualView *view)
     }
   g_clear_object (&iter);
 
-  menu = empathy_individual_menu_new (individual, priv->individual_features);
+  menu = empathy_individual_menu_new (individual, priv->individual_features,
+      priv->store);
 
   /* Remove contact */
   if ((priv->view_features &
index edc5463c99092d8b9be88a5cb92b10d0161dfe36..a02b8b144f662c5e9ecc25de5540ba2f25da141e 100644 (file)
@@ -170,6 +170,24 @@ empathy_client_factory_dup_connection_features (TpSimpleClientFactory *factory,
   return features;
 }
 
+static GArray *
+empathy_client_factory_dup_contact_features (TpSimpleClientFactory *factory,
+        TpConnection *connection)
+{
+  GArray *features;
+  TpContactFeature feature;
+
+  features = chainup->dup_contact_features (factory, connection);
+
+  /* Needed by empathy_individual_add_menu_item_new to check if a contact is
+   * already in the contact list. This feature is pretty cheap to prepare as
+   * it doesn't prepare the full roster. */
+  feature = TP_CONTACT_FEATURE_SUBSCRIPTION_STATES;
+  g_array_append_val (features, feature);
+
+  return features;
+}
+
 static void
 empathy_client_factory_class_init (EmpathyClientFactoryClass *cls)
 {
@@ -184,6 +202,9 @@ empathy_client_factory_class_init (EmpathyClientFactoryClass *cls)
 
   simple_class->dup_connection_features =
     empathy_client_factory_dup_connection_features;
+
+  simple_class->dup_contact_features =
+    empathy_client_factory_dup_contact_features;
 }
 
 static void
index 7dd6310482c3a3145ac64851cf5cdd71db4e74c4..2f73acf92dcb8b235b6076f7f5c814eaee4f096a 100644 (file)
@@ -2472,7 +2472,7 @@ empathy_main_window_init (EmpathyMainWindow *window)
        priv->individual_view = empathy_individual_view_new (
                        priv->individual_store,
                        EMPATHY_INDIVIDUAL_VIEW_FEATURE_ALL ^ EMPATHY_INDIVIDUAL_VIEW_FEATURE_PERSONA_DROP,
-                       EMPATHY_INDIVIDUAL_FEATURE_ALL);
+                       EMPATHY_INDIVIDUAL_FEATURE_ALL ^ EMPATHY_INDIVIDUAL_FEATURE_ADD_CONTACT);
 
        gtk_widget_show (GTK_WIDGET (priv->individual_view));
        gtk_container_add (GTK_CONTAINER (sw),