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/contactsview.cpp b/src/contactsview.cpp
index 865667d..dcaedd3 100644
--- a/src/contactsview.cpp
+++ b/src/contactsview.cpp
@@ -251,6 +251,13 @@
 }
 
 static void
+call_contactmethod(G_GNUC_UNUSED GtkWidget *item, ContactMethod *cm)
+{
+    g_return_if_fail(cm);
+    place_new_call(cm);
+}
+
+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);
@@ -342,10 +349,45 @@
      * if depth > 2, then its a contact method, so only offer to copy the number
      */
     if (depth == 2) {
-        QVariant var_c = idx.data(static_cast<int>(Person::Role::Object));
+        QVariant var_c = idx.data(static_cast<int>(Ring::Role::Object));
         if (var_c.isValid()) {
             Person *c = var_c.value<Person *>();
 
+                /* call */
+                /* possiblity for multiple numbers */
+                auto cms = c->phoneNumbers();
+                if (cms.size() == 1) {
+                    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(call_contactmethod),
+                                     cms.at(0));
+                } else if (cms.size() > 1) {
+                    // maybe this is not needed since there is the depth > 2 option
+                    auto call_item = gtk_menu_item_new_with_mnemonic(_("_Call"));
+                    gtk_menu_shell_append(GTK_MENU_SHELL(menu), call_item);
+                    auto call_menu = gtk_menu_new();
+                    gtk_menu_item_set_submenu(GTK_MENU_ITEM(call_item), call_menu);
+                    for (int i = 0; i < cms.size(); ++i) {
+                        gchar *number = nullptr;
+                        if (cms.at(i)->category()) {
+                            // try to get the number category, eg: "home"
+                            number = g_strdup_printf("(%s) %s", cms.at(i)->category()->name().toUtf8().constData(),
+                                                              cms.at(i)->uri().toUtf8().constData());
+                        } else {
+                            number = g_strdup_printf("%s", cms.at(i)->uri().toUtf8().constData());
+                        }
+                        auto item = gtk_menu_item_new_with_label(number);
+                        g_free(number);
+                        gtk_menu_shell_append(GTK_MENU_SHELL(call_menu), item);
+                        g_signal_connect(item,
+                                         "activate",
+                                         G_CALLBACK(call_contactmethod),
+                                         cms.at(i));
+                    }
+                }
+
             /* copy name */
             gchar *name = g_strdup_printf("%s", c->formattedName().toUtf8().constData());
             GtkWidget *copy_name_item = gtk_menu_item_new_with_mnemonic(_("_Copy name"));
@@ -379,11 +421,11 @@
 
         }
     } else if (depth > 2) {
-        /* copy number */
         QVariant var_n = idx.data(static_cast<int>(ContactMethod::Role::Object));
         if (var_n.isValid()) {
-            ContactMethod *n = var_n.value<ContactMethod *>();
-            gchar *number = g_strdup_printf("%s",n->uri().toUtf8().constData());
+            /* copy number */
+            ContactMethod *cm = var_n.value<ContactMethod *>();
+            gchar *number = g_strdup_printf("%s",cm->uri().toUtf8().constData());
             GtkWidget *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);
@@ -391,6 +433,14 @@
                              "activate",
                              G_CALLBACK(copy_contact_info),
                              NULL);
+
+            /* call */
+            item = gtk_menu_item_new_with_mnemonic(_("_Call"));
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+            g_signal_connect(item,
+                             "activate",
+                             G_CALLBACK(call_contactmethod),
+                             cm);
         }
     }
 
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);