]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/empathy-individual-view.c
Merge branch 'folks-async-and-prepare'
[empathy.git] / libempathy-gtk / empathy-individual-view.c
index 012b8ec15b25cb77badfb46fd081d391f531867e..7083b238b6973edbf10c846890173ada095e2159 100644 (file)
@@ -143,9 +143,6 @@ individual_view_is_visible_individual (EmpathyIndividualView *self,
   EmpathyIndividualViewPriv *priv = GET_PRIV (self);
   EmpathyLiveSearch *live = EMPATHY_LIVE_SEARCH (priv->search_widget);
   const gchar *str;
-  const gchar *p;
-  gchar *dup_str = NULL;
-  gboolean visible;
   GList *personas, *l;
 
   g_assert (live != NULL);
@@ -159,6 +156,10 @@ individual_view_is_visible_individual (EmpathyIndividualView *self,
   personas = folks_individual_get_personas (individual);
   for (l = personas; l; l = l->next)
     {
+      const gchar *p;
+      gchar *dup_str = NULL;
+      gboolean visible;
+
       str = folks_persona_get_uid (l->data);
       p = strstr (str, "@");
       if (p != NULL)
@@ -233,6 +234,19 @@ individual_view_filter_visible_func (GtkTreeModel *model,
   return FALSE;
 }
 
+static void
+individual_view_tooltip_destroy_cb (GtkWidget *widget,
+    EmpathyIndividualView *view)
+{
+  EmpathyIndividualViewPriv *priv = GET_PRIV (view);
+
+  if (priv->tooltip_widget != NULL)
+    {
+      DEBUG ("Tooltip destroyed");
+      tp_clear_object (&priv->tooltip_widget);
+    }
+}
+
 static gboolean
 individual_view_query_tooltip_cb (EmpathyIndividualView *view,
     gint x,
@@ -241,48 +255,86 @@ individual_view_query_tooltip_cb (EmpathyIndividualView *view,
     GtkTooltip *tooltip,
     gpointer user_data)
 {
+  EmpathyIndividualViewPriv *priv;
   FolksIndividual *individual;
   GtkTreeModel *model;
   GtkTreeIter iter;
   GtkTreePath *path;
   static gint running = 0;
   gboolean ret = FALSE;
+  EmpathyContact *contact;
+
+  priv = GET_PRIV (view);
 
   /* Avoid an infinite loop. See GNOME bug #574377 */
   if (running > 0)
-    {
-      return FALSE;
-    }
+    return FALSE;
+
   running++;
 
   /* Don't show the tooltip if there's already a popup menu */
   if (gtk_menu_get_for_attach_widget (GTK_WIDGET (view)) != NULL)
-    {
-      goto OUT;
-    }
+    goto OUT;
 
   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (view), &x, &y,
           keyboard_mode, &model, &path, &iter))
-    {
-      goto OUT;
-    }
+    goto OUT;
 
   gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (view), tooltip, path);
   gtk_tree_path_free (path);
 
   gtk_tree_model_get (model, &iter,
-      EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual, -1);
+      EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual,
+      -1);
   if (individual == NULL)
+    goto OUT;
+
+  contact = empathy_contact_dup_from_folks_individual (individual);
+  g_object_unref (individual);
+
+  if (contact == NULL)
+    goto OUT;
+
+  if (priv->tooltip_widget == NULL)
     {
-      goto OUT;
+      priv->tooltip_widget = empathy_contact_widget_new (contact,
+          EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP |
+          EMPATHY_CONTACT_WIDGET_SHOW_LOCATION);
+      gtk_container_set_border_width (GTK_CONTAINER (priv->tooltip_widget), 8);
+      g_object_ref (priv->tooltip_widget);
+      g_signal_connect (priv->tooltip_widget, "destroy",
+          G_CALLBACK (individual_view_tooltip_destroy_cb), view);
+      gtk_widget_show (priv->tooltip_widget);
     }
+  else
+    empathy_contact_widget_set_contact (priv->tooltip_widget, contact);
 
+  gtk_tooltip_set_custom (tooltip, priv->tooltip_widget);
+  ret = TRUE;
+
+  g_object_unref (contact);
 OUT:
   running--;
 
   return ret;
 }
 
+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
 individual_view_handle_drag (EmpathyIndividualView *self,
     FolksIndividual *individual,
@@ -299,29 +351,26 @@ individual_view_handle_drag (EmpathyIndividualView *self,
   if (!tp_strdiff (new_group, EMPATHY_INDIVIDUAL_STORE_FAVORITE))
     {
       /* Mark contact as favourite */
-
-      /* TODO: implement this */
-      DEBUG ("adding individual to favourites not fully implemented");
-
+      folks_favourite_set_is_favourite (FOLKS_FAVOURITE (individual), TRUE);
       return;
     }
 
   if (!tp_strdiff (old_group, EMPATHY_INDIVIDUAL_STORE_FAVORITE))
     {
       /* Remove contact as favourite */
-
-      /* TODO: implement this */
-      DEBUG ("removing individual from favourites not fully " "implemented");
+      folks_favourite_set_is_favourite (FOLKS_FAVOURITE (individual), FALSE);
 
       /* Don't try to remove it */
       old_group = NULL;
     }
 
   if (new_group != NULL)
-    folks_groups_change_group (FOLKS_GROUPS (individual), new_group, TRUE);
+    folks_groups_change_group (FOLKS_GROUPS (individual), new_group, TRUE,
+        groups_change_group_cb, NULL);
 
   if (old_group != NULL && action == GDK_ACTION_MOVE)
-    folks_groups_change_group (FOLKS_GROUPS (individual), old_group, FALSE);
+    folks_groups_change_group (FOLKS_GROUPS (individual), old_group, FALSE,
+        groups_change_group_cb, NULL);
 }
 
 static gboolean
@@ -432,21 +481,21 @@ individual_view_file_drag_received (GtkWidget *view,
   GtkTreeIter iter;
   const gchar *sel_data;
   FolksIndividual *individual;
+  EmpathyContact *contact;
 
   sel_data = (const gchar *) gtk_selection_data_get_data (selection);
 
   gtk_tree_model_get_iter (model, &iter, path);
   gtk_tree_model_get (model, &iter,
       EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual, -1);
-  if (!individual)
-    {
-      return FALSE;
-    }
+  if (individual == NULL)
+    return FALSE;
 
-  /* TODO: implement this */
-  DEBUG ("file transfer not implemented");
+  contact = empathy_contact_dup_from_folks_individual (individual);
+  empathy_send_file_from_uri_list (contact, sel_data);
 
   g_object_unref (individual);
+  tp_clear_object (&contact);
 
   return TRUE;
 }
@@ -525,18 +574,16 @@ individual_view_drag_motion (GtkWidget *widget,
   is_row = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
       x, y, &path, NULL, NULL, NULL);
 
-  cleanup &= (!dm);
+  cleanup &= (dm == NULL);
 
   if (is_row)
     {
       cleanup &= (dm && gtk_tree_path_compare (dm->path, path) != 0);
-      is_different = (!dm || (dm
+      is_different = ((dm == NULL) || ((dm != NULL)
               && gtk_tree_path_compare (dm->path, path) != 0));
     }
   else
-    {
-      cleanup &= FALSE;
-    }
+    cleanup &= FALSE;
 
   if (path == NULL)
     {
@@ -596,17 +643,27 @@ individual_view_drag_motion (GtkWidget *widget,
          not groups.
        */
       FolksIndividual *individual;
+      EmpathyCapabilities caps = EMPATHY_CAPABILITIES_NONE;
+
       gtk_tree_model_get (model, &iter,
           EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual, -1);
+      if (individual != NULL)
+        {
+          EmpathyContact *contact = NULL;
+
+          contact = empathy_contact_dup_from_folks_individual (individual);
+          caps = empathy_contact_get_capabilities (contact);
+
+          tp_clear_object (&contact);
+        }
+
       if (individual != NULL &&
           folks_individual_is_online (individual) &&
-          (folks_individual_get_capabilities (individual) &
-              FOLKS_CAPABILITIES_FLAGS_FILE_TRANSFER))
+          (caps & EMPATHY_CAPABILITIES_FT))
         {
           gdk_drag_status (context, GDK_ACTION_COPY, time_);
           gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
               path, GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
-          g_object_unref (individual);
         }
       else
         {
@@ -614,12 +671,13 @@ individual_view_drag_motion (GtkWidget *widget,
           gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), NULL, 0);
           retval = FALSE;
         }
+
+      if (individual != NULL)
+        g_object_unref (individual);
     }
 
   if (!is_different && !cleanup)
-    {
-      return retval;
-    }
+    return retval;
 
   if (dm)
     {
@@ -665,9 +723,7 @@ individual_view_drag_begin (GtkWidget *widget,
 
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
   if (!gtk_tree_selection_get_selected (selection, &model, &iter))
-    {
-      return;
-    }
+    return;
 
   path = gtk_tree_model_get_path (model, &iter);
   priv->drag_row = gtk_tree_row_reference_new (model, path);
@@ -691,16 +747,12 @@ individual_view_drag_data_get (GtkWidget *widget,
   priv = GET_PRIV (widget);
 
   model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
-  if (!priv->drag_row)
-    {
-      return;
-    }
+  if (priv->drag_row == NULL)
+    return;
 
   src_path = gtk_tree_row_reference_get_path (priv->drag_row);
-  if (!src_path)
-    {
-      return;
-    }
+  if (src_path == NULL)
+    return;
 
   if (!gtk_tree_model_get_iter (model, &iter, src_path))
     {
@@ -712,10 +764,8 @@ individual_view_drag_data_get (GtkWidget *widget,
 
   individual =
       empathy_individual_view_dup_selected (EMPATHY_INDIVIDUAL_VIEW (widget));
-  if (!individual)
-    {
-      return;
-    }
+  if (individual == NULL)
+    return;
 
   individual_id = folks_individual_get_id (individual);
 
@@ -726,6 +776,8 @@ individual_view_drag_data_get (GtkWidget *widget,
           (guchar *) individual_id, strlen (individual_id) + 1);
       break;
     }
+
+  g_object_unref (individual);
 }
 
 static void
@@ -770,20 +822,17 @@ individual_view_popup_menu_idle_cb (gpointer user_data)
   GtkWidget *menu;
 
   menu = empathy_individual_view_get_individual_menu (data->view);
-  if (!menu)
-    {
-      menu = empathy_individual_view_get_group_menu (data->view);
-    }
+  if (menu == NULL)
+    menu = empathy_individual_view_get_group_menu (data->view);
 
-  if (menu)
+  if (menu != NULL)
     {
-      g_signal_connect (menu, "deactivate",
-          G_CALLBACK (gtk_menu_detach), NULL);
-      gtk_menu_attach_to_widget (GTK_MENU (menu),
-          GTK_WIDGET (data->view), NULL);
+      g_signal_connect (menu, "deactivate", G_CALLBACK (gtk_menu_detach), NULL);
+      gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (data->view),
+          NULL);
       gtk_widget_show (menu);
-      gtk_menu_popup (GTK_MENU (menu),
-          NULL, NULL, NULL, NULL, data->button, data->time);
+      gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, data->button,
+          data->time);
       g_object_ref_sink (menu);
       g_object_unref (menu);
     }
@@ -843,21 +892,18 @@ individual_view_row_activated (GtkTreeView *view,
   GtkTreeIter iter;
 
   if (!(priv->individual_features & EMPATHY_CONTACT_FEATURE_CHAT))
-    {
-      return;
-    }
+    return;
 
-  model = GTK_TREE_MODEL (priv->store);
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
   gtk_tree_model_get_iter (model, &iter, path);
   gtk_tree_model_get (model, &iter,
       EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual, -1);
 
-  if (!individual)
+  if (individual == NULL)
     return;
 
-  contact = empathy_contact_from_folks_individual (individual);
-
-  if (contact)
+  contact = empathy_contact_dup_from_folks_individual (individual);
+  if (contact != NULL)
     {
       DEBUG ("Starting a chat");
 
@@ -866,6 +912,7 @@ individual_view_row_activated (GtkTreeView *view,
     }
 
   g_object_unref (individual);
+  tp_clear_object (&contact);
 }
 
 static void
@@ -879,6 +926,7 @@ individual_view_call_activated_cb (EmpathyCellRendererActivatable *cell,
   FolksIndividual *individual;
   GdkEventButton *event;
   GtkMenuShell *shell;
+  GtkWidget *item;
 
   model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
   if (!gtk_tree_model_get_iter_from_string (model, &iter, path_string))
@@ -895,12 +943,14 @@ individual_view_call_activated_cb (EmpathyCellRendererActivatable *cell,
   shell = GTK_MENU_SHELL (menu);
 
   /* audio */
-  /* TODO: implement */
-  DEBUG ("audio call menu item unimplemented");
+  item = empathy_individual_audio_call_menu_item_new (individual);
+  gtk_menu_shell_append (shell, item);
+  gtk_widget_show (item);
 
   /* video */
-  /* TODO: implement */
-  DEBUG ("video call menu item unimplemented");
+  item = empathy_individual_video_call_menu_item_new (individual);
+  gtk_menu_shell_append (shell, item);
+  gtk_widget_show (item);
 
   g_signal_connect (menu, "deactivate", G_CALLBACK (gtk_menu_detach), NULL);
   gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (view), NULL);
@@ -940,9 +990,7 @@ individual_view_cell_set_background (EmpathyIndividualView *view,
       g_object_set (cell, "cell-background-gdk", &color, NULL);
     }
   else
-    {
-      g_object_set (cell, "cell-background-gdk", NULL, NULL);
-    }
+    g_object_set (cell, "cell-background-gdk", NULL, NULL);
 }
 
 static void
@@ -966,10 +1014,7 @@ individual_view_pixbuf_cell_data_func (GtkTreeViewColumn *tree_column,
       "pixbuf", pixbuf,
       NULL);
 
-  if (pixbuf != NULL)
-    {
-      g_object_unref (pixbuf);
-    }
+  tp_clear_object (&pixbuf);
 
   individual_view_cell_set_background (view, cell, is_group, is_active);
 }
@@ -1009,8 +1054,7 @@ out:
       "pixbuf", pixbuf,
       NULL);
 
-  if (pixbuf != NULL)
-    g_object_unref (pixbuf);
+  tp_clear_object (&pixbuf);
 
   g_free (name);
 }
@@ -1063,10 +1107,7 @@ individual_view_avatar_cell_data_func (GtkTreeViewColumn *tree_column,
       "pixbuf", pixbuf,
       NULL);
 
-  if (pixbuf)
-    {
-      g_object_unref (pixbuf);
-    }
+  tp_clear_object (&pixbuf);
 
   individual_view_cell_set_background (view, cell, is_group, is_active);
 }
@@ -1120,9 +1161,7 @@ individual_view_expander_cell_data_func (GtkTreeViewColumn *column,
           NULL);
     }
   else
-    {
-      g_object_set (cell, "visible", FALSE, NULL);
-    }
+    g_object_set (cell, "visible", FALSE, NULL);
 
   individual_view_cell_set_background (view, cell, is_group, is_active);
 }
@@ -1334,7 +1373,6 @@ individual_view_expand_idle_cb (gpointer user_data)
   if (path == NULL)
     goto done;
 
-
   g_signal_handlers_block_by_func (data->view,
     individual_view_row_expand_or_collapse_cb,
     GINT_TO_POINTER (data->expand));
@@ -1449,7 +1487,6 @@ individual_view_constructed (GObject *object)
 {
   EmpathyIndividualView *view = EMPATHY_INDIVIDUAL_VIEW (object);
   EmpathyIndividualViewPriv *priv = GET_PRIV (view);
-
   GtkCellRenderer *cell;
   GtkTreeViewColumn *col;
   guint i;
@@ -1471,6 +1508,13 @@ individual_view_constructed (GObject *object)
   tp_g_signal_connect_object (priv->store, "row-deleted",
       G_CALLBACK (individual_view_store_row_deleted_cb), view, 0);
 
+  tp_g_signal_connect_object (priv->store, "row-changed",
+    G_CALLBACK (individual_view_store_row_changed_cb), view, 0);
+  tp_g_signal_connect_object (priv->store, "row-inserted",
+    G_CALLBACK (individual_view_store_row_changed_cb), view, 0);
+  tp_g_signal_connect_object (priv->store, "row-deleted",
+    G_CALLBACK (individual_view_store_row_deleted_cb), view, 0);
+
   /* Setup view */
   /* Setting reorderable is a hack that gets us row previews as drag icons
      for free.  We override all the drag handlers.  It's tricky to get the
@@ -1633,26 +1677,10 @@ individual_view_dispose (GObject *object)
   EmpathyIndividualView *view = EMPATHY_INDIVIDUAL_VIEW (object);
   EmpathyIndividualViewPriv *priv = GET_PRIV (view);
 
-  if (priv->store != NULL)
-    {
-      g_object_unref (priv->store);
-      priv->store = NULL;
-    }
-  if (priv->filter != NULL)
-    {
-      g_object_unref (priv->filter);
-      priv->filter = NULL;
-    }
-  if (priv->tooltip_widget != NULL)
-    {
-      gtk_widget_destroy (priv->tooltip_widget);
-      priv->tooltip_widget = NULL;
-    }
-  if (priv->file_targets != NULL)
-    {
-      gtk_target_list_unref (priv->file_targets);
-      priv->file_targets = NULL;
-    }
+  tp_clear_object (&priv->store);
+  tp_clear_object (&priv->filter);
+  tp_clear_pointer (&priv->tooltip_widget, gtk_widget_destroy);
+  tp_clear_pointer (&priv->file_targets, gtk_target_list_unref);
 
   empathy_individual_view_set_live_search (view, NULL);
 
@@ -1830,9 +1858,7 @@ empathy_individual_view_dup_selected (EmpathyIndividualView *view)
 
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
   if (!gtk_tree_selection_get_selected (selection, &model, &iter))
-    {
-      return NULL;
-    }
+    return NULL;
 
   gtk_tree_model_get (model, &iter,
       EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual, -1);
@@ -1855,9 +1881,7 @@ empathy_individual_view_get_flags (EmpathyIndividualView *view)
 
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
   if (!gtk_tree_selection_get_selected (selection, &model, &iter))
-    {
-      return 0;
-    }
+    return 0;
 
   gtk_tree_model_get (model, &iter,
       EMPATHY_INDIVIDUAL_STORE_COL_FLAGS, &flags, -1);
@@ -1883,9 +1907,7 @@ empathy_individual_view_get_selected_group (EmpathyIndividualView *view,
 
   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
   if (!gtk_tree_selection_get_selected (selection, &model, &iter))
-    {
-      return NULL;
-    }
+    return NULL;
 
   gtk_tree_model_get (model, &iter,
       EMPATHY_INDIVIDUAL_STORE_COL_IS_GROUP, &is_group,
@@ -1935,7 +1957,7 @@ individual_view_group_remove_activate_cb (GtkMenuItem *menuitem,
   gchar *group;
 
   group = empathy_individual_view_get_selected_group (view, NULL);
-  if (group)
+  if (group != NULL)
     {
       gchar *text;
       GtkWindow *parent;
@@ -1947,8 +1969,10 @@ individual_view_group_remove_activate_cb (GtkMenuItem *menuitem,
       if (individual_view_remove_dialog_show (parent, _("Removing group"),
               text))
         {
-          /* TODO: implement */
-          DEBUG ("removing group unimplemented");
+          EmpathyIndividualManager *manager =
+              empathy_individual_manager_dup_singleton ();
+          empathy_individual_manager_remove_group (manager, group);
+          g_object_unref (G_OBJECT (manager));
         }
 
       g_free (text);
@@ -1971,9 +1995,7 @@ empathy_individual_view_get_group_menu (EmpathyIndividualView *view)
 
   if (!(priv->view_features & (EMPATHY_INDIVIDUAL_VIEW_FEATURE_GROUPS_RENAME |
               EMPATHY_INDIVIDUAL_VIEW_FEATURE_GROUPS_REMOVE)))
-    {
-      return NULL;
-    }
+    return NULL;
 
   group = empathy_individual_view_get_selected_group (view, &is_fake_group);
   if (!group || is_fake_group)
@@ -2021,7 +2043,7 @@ individual_view_remove_activate_cb (GtkMenuItem *menuitem,
 
   individual = empathy_individual_view_dup_selected (view);
 
-  if (individual)
+  if (individual != NULL)
     {
       gchar *text;
       GtkWindow *parent;
@@ -2059,14 +2081,12 @@ empathy_individual_view_get_individual_menu (EmpathyIndividualView *view)
   g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_VIEW (view), NULL);
 
   individual = empathy_individual_view_dup_selected (view);
-  if (!individual)
-    {
-      return NULL;
-    }
+  if (individual == NULL)
+    return NULL;
+
   flags = empathy_individual_view_get_flags (view);
 
-  /* TODO: implement (create the menu here */
-  DEBUG ("individual menu not implemented");
+  menu = empathy_individual_menu_new (individual, priv->individual_features);
 
   /* Remove contact */
   if (priv->view_features &
@@ -2075,10 +2095,8 @@ empathy_individual_view_get_individual_menu (EmpathyIndividualView *view)
     {
 
       /* create the menu if required, or just add a separator */
-      if (!menu)
-        {
-          menu = gtk_menu_new ();
-        }
+      if (menu == NULL)
+        menu = gtk_menu_new ();
       else
         {
           item = gtk_separator_menu_item_new ();