Add the possibility to call and copy name/number on all views

Now possible to call from the contact view
Now possible to call, copy the name and number in the history view

Also fixes use after free issue

Change-Id: Ice67750b3ed66b14cd0f41909f3ee8804690e836
Tuleap: #395
Tuleap: #462
diff --git a/src/historyview.cpp b/src/historyview.cpp
index 9e3a655..00b9e28 100644
--- a/src/historyview.cpp
+++ b/src/historyview.cpp
@@ -36,6 +36,8 @@
 #include <QtCore/QItemSelectionModel>
 #include "utils/menus.h"
 
+static constexpr const char* COPY_DATA_KEY = "copy_data";
+
 struct _HistoryView
 {
     GtkTreeView parent;
@@ -127,17 +129,20 @@
 }
 
 static void
-copy_history_item(G_GNUC_UNUSED GtkWidget *item, GtkTreeView *treeview)
+call_contactmethod(G_GNUC_UNUSED GtkWidget *item, ContactMethod *cm)
 {
-    GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
-    QModelIndex idx = get_index_from_selection(selection);
+    g_return_if_fail(cm);
+    place_new_call(cm);
+}
 
-    if (idx.isValid()) {
-        GtkClipboard* clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
-
-        const gchar* number = idx.data(static_cast<int>(Call::Role::Number)).toString().toUtf8().constData();
-        gtk_clipboard_set_text(clip, number, -1);
-    }
+static void
+copy_contact_info(GtkWidget *item, G_GNUC_UNUSED gpointer user_data)
+{
+    gpointer data = g_object_get_data(G_OBJECT(item), COPY_DATA_KEY);
+    g_return_if_fail(data);
+    gchar* text = (gchar *)data;
+    GtkClipboard* clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
+    gtk_clipboard_set_text(clip, text, -1);
 }
 
 /* TODO: can't seem to delete just one item for now, add when supported in backend
@@ -158,7 +163,7 @@
 history_popup_menu(G_GNUC_UNUSED GtkWidget *widget, GdkEventButton *event, GtkTreeView *treeview)
 {
     /* build popup menu when right clicking on history item
-     * user should be able to copy the "number",
+     * user should be able to call, copy the "name" or the "number",
      * delete history item or all of the history,
      * and eventualy add the number to a contact
      */
@@ -167,12 +172,62 @@
     if (event->button != BUTTON_RIGHT_CLICK || event->type != GDK_BUTTON_PRESS)
         return FALSE;
 
+    /* check if the selected item is a call */
+    auto selection = gtk_tree_view_get_selection(treeview);
+    const auto& idx = get_index_from_selection(selection);
+    const auto& var_c = idx.data(static_cast<int>(Call::Role::Object));
+    if (!idx.isValid() || !var_c.isValid())
+        return FALSE;
+    auto call = var_c.value<Call *>();
+    if (call == nullptr)
+        return FALSE;
+
     GtkWidget *menu = gtk_menu_new();
 
-    /* copy */
-    GtkWidget *item = gtk_menu_item_new_with_mnemonic(_("_Copy"));
+    /* call */
+    auto item = gtk_menu_item_new_with_mnemonic(_("_Call"));
     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-    g_signal_connect(item, "activate", G_CALLBACK(copy_history_item), treeview);
+    g_signal_connect(item,
+                     "activate",
+                     G_CALLBACK(call_contactmethod),
+                     call->peerContactMethod());
+
+    /* copy name */
+    QVariant name_var = idx.data(static_cast<int>(Ring::Role::Name));
+    if (name_var.isValid()) {
+        gchar *name = g_strdup_printf("%s", name_var.value<QString>().toUtf8().constData());
+        item = gtk_menu_item_new_with_mnemonic(_("_Copy name"));
+        gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+        g_object_set_data_full(G_OBJECT(item), COPY_DATA_KEY, name, (GDestroyNotify)g_free);
+        g_signal_connect(item, "activate", G_CALLBACK(copy_contact_info), NULL);
+    }
+
+     /* copy number */
+     QVariant number_var = idx.data(static_cast<int>(Ring::Role::Number));
+     if (number_var.isValid()) {
+         gchar *number = g_strdup_printf("%s", number_var.value<QString>().toUtf8().constData());
+         item = gtk_menu_item_new_with_mnemonic(_("_Copy number"));
+         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+         g_object_set_data_full(G_OBJECT(item), COPY_DATA_KEY, number, (GDestroyNotify)g_free);
+         g_signal_connect(item, "activate", G_CALLBACK(copy_contact_info), NULL);
+     }
+
+    /* get the contact method and check if it is already linked to a person,
+     * if not, then offer to either add to a new or existing contact */
+    auto contactmethod = call->peerContactMethod();
+    if (!contact_method_has_contact(contactmethod)) {
+        GtkTreeIter iter;
+        GtkTreeModel *model;
+        gtk_tree_selection_get_selected(selection, &model, &iter);
+        auto path = gtk_tree_model_get_path(model, &iter);
+        auto column = gtk_tree_view_get_column(treeview, 0);
+        GdkRectangle rect;
+        gtk_tree_view_get_cell_area(treeview, path, column, &rect);
+        gtk_tree_view_convert_bin_window_to_widget_coords(treeview, rect.x, rect.y, &rect.x, &rect.y);
+        gtk_tree_path_free(path);
+        auto add_to = menu_item_add_to_contact(contactmethod, GTK_WIDGET(treeview), &rect);
+        gtk_menu_shell_append(GTK_MENU_SHELL(menu), add_to);
+    }
 
     /* TODO: delete history entry
      * gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
@@ -181,31 +236,6 @@
      * g_signal_connect(item, "activate", G_CALLBACK(delete_history_item), treeview);
      */
 
-    /* check if the selected item is a call, if so get the contact method and
-     * check if it is already linked to a person, if not, then offer to either
-     * add to a new or existing contact */
-    auto selection = gtk_tree_view_get_selection(treeview);
-    const auto& idx = get_index_from_selection(selection);
-    const auto& var_c = idx.data(static_cast<int>(Call::Role::Object));
-    if (idx.isValid() && var_c.isValid()) {
-        if (auto call = var_c.value<Call *>()) {
-            auto contactmethod = call->peerContactMethod();
-            if (!contact_method_has_contact(contactmethod)) {
-                GtkTreeIter iter;
-                GtkTreeModel *model;
-                gtk_tree_selection_get_selected(selection, &model, &iter);
-                auto path = gtk_tree_model_get_path(model, &iter);
-                auto column = gtk_tree_view_get_column(treeview, 0);
-                GdkRectangle rect;
-                gtk_tree_view_get_cell_area(treeview, path, column, &rect);
-                gtk_tree_view_convert_bin_window_to_widget_coords(treeview, rect.x, rect.y, &rect.x, &rect.y);
-                gtk_tree_path_free(path);
-                auto add_to = menu_item_add_to_contact(contactmethod, GTK_WIDGET(treeview), &rect);
-                gtk_menu_shell_append(GTK_MENU_SHELL(menu), add_to);
-            }
-        }
-    }
-
     /* show menu */
     gtk_widget_show_all(menu);
     gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);