From cb10c6d3c4ee7c568575870d627f3b707d79b3f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1?=
 =?UTF-8?q?=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Fri, 16 Dec 2011 13:13:59 +0400
Subject: [PATCH 2/3] Make metadata copyable

---
 contrib/gnunet_fs_gtk_main_window.glade |   16 +++
 src/fs/gnunet-fs-gtk-event_handler.c    |  176 +++++++++++++++++++++++++++++++
 src/fs/gnunet-fs-gtk.c                  |    6 +
 3 files changed, 198 insertions(+), 0 deletions(-)

diff --git a/contrib/gnunet_fs_gtk_main_window.glade b/contrib/gnunet_fs_gtk_main_window.glade
index c741281..a47a445 100644
--- a/contrib/gnunet_fs_gtk_main_window.glade
+++ b/contrib/gnunet_fs_gtk_main_window.glade
@@ -604,6 +604,8 @@
                         <property name="search_column">0</property>
                         <property name="rubber_banding">True</property>
                         <property name="enable_grid_lines">both</property>
+                        <signal name="button-press-event" handler="GNUNET_GTK_main_window_metadata_treeview_button_press_event_cb" swapped="no"/>
+                        <signal name="popup-menu" handler="GNUNET_GTK_main_window_metadata_treeview_popup_menu_cb" swapped="no"/>
                         <child>
                           <object class="GtkTreeViewColumn" id="GNUNET_GTK_main_window_metadata_type_column">
                             <property name="sizing">autosize</property>
@@ -849,6 +851,20 @@
       <column type="gchararray"/>
     </columns>
   </object>
+  <object class="GtkMenu" id="metadata_popup_menu">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkMenuItem" id="Copy selection">
+        <property name="use_action_appearance">False</property>
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Copy selection</property>
+        <property name="use_underline">True</property>
+        <signal name="activate" handler="metadata_copy_selection_activated" swapped="no"/>
+      </object>
+    </child>
+  </object>
   <object class="GtkWindow" id="namespace_selector_window">
     <property name="can_focus">False</property>
     <property name="events">GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
diff --git a/src/fs/gnunet-fs-gtk-event_handler.c b/src/fs/gnunet-fs-gtk-event_handler.c
index 74c3ab5..8565bd0 100644
--- a/src/fs/gnunet-fs-gtk-event_handler.c
+++ b/src/fs/gnunet-fs-gtk-event_handler.c
@@ -1934,6 +1934,182 @@ GNUNET_GTK_main_window_notebook_switch_page_cb (GtkWidget * dummy,
   gtk_list_store_clear (ms);
 }
 
+static void
+copy_metadata_to_clipboard (GtkTreeModel *model, GtkTreePath *path,
+    GtkTreeIter *iter, gpointer user_data)
+{
+  gchar *type, *value;
+  GList **l = (GList **) user_data;
+
+  gtk_tree_model_get (model, iter, 2, &type, 3, &value, -1);
+
+  *l = g_list_prepend (*l, type);
+  *l = g_list_prepend (*l, value);
+}
+
+void
+metadata_copy_selection_activated (GtkMenuItem *menuitem, gpointer user_data)
+{
+  GtkBuilder *builder;
+  GtkTreeView *tree;
+  GtkClipboard *cb;
+  GList *pairs = NULL, *l, *next, *value, *type;
+  guint total_len;
+  gchar *s, *p;
+
+  builder = GTK_BUILDER (user_data);
+  tree = GTK_TREE_VIEW (gtk_builder_get_object (builder,
+      "GNUNET_GTK_main_window_metadata_treeview"));
+
+  gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (tree),
+      copy_metadata_to_clipboard, &pairs);
+
+  total_len = 0;
+  pairs = g_list_reverse (pairs);
+  for (l = pairs; l; l = next)
+  {
+    type = l;
+    value = l->next;
+    if (!value)
+      break;
+    next = value->next;
+    total_len += strlen ((gchar *) type->data)
+        + strlen ((gchar *) value->data) + 2 /* ": " */ + (next ? 1 : 0) /* "\n" */;
+  }
+  if (total_len > 0)
+  {
+    total_len += 1; /* "\0" */
+    s = g_new0 (gchar, total_len);
+    p = s;
+    for (l = pairs; l; l = next)
+    {
+      type = l;
+      value = l->next;
+      if (value)
+      {
+        next = value->next;
+        p = g_stpcpy (p, (gchar *) type->data);
+        p = g_stpcpy (p, ": ");
+        p = g_stpcpy (p, (gchar *) value->data);
+        if (next)
+          p = g_stpcpy (p, "\n");
+      }
+      else
+        next = NULL;
+    }
+  }
+  g_list_foreach (pairs, (GFunc) g_free, NULL);
+  g_list_free (pairs);
+  pairs = NULL;
+
+  if (total_len > 0)
+  {
+    cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+    gtk_clipboard_set_text (cb, s, -1);
+    gtk_clipboard_store (cb);
+    g_free (s);
+  }
+}
+
+void
+metadata_menu_popup_position (GtkMenu *menu, gint *x, gint *y, gboolean *push_in,
+    gpointer user_data)
+{
+  GtkBuilder *builder;
+  GtkTreeView *tree;
+  GtkTreeSelection *sel;
+  GList *rows;
+  GtkTreePath *p;
+  GtkAllocation tree_allocation;
+  GdkWindow *main_window_gdk;
+  gint mwg_x, mwg_y, t_x, t_y, popup_x, popup_y;
+
+  builder = GTK_BUILDER (user_data);
+
+  tree = GTK_TREE_VIEW (gtk_builder_get_object (builder,
+      "GNUNET_GTK_main_window_metadata_treeview"));
+
+  gtk_widget_get_allocation (GTK_WIDGET (tree), &tree_allocation);
+
+  main_window_gdk = gtk_widget_get_window (GTK_WIDGET (tree));
+
+  gdk_window_get_origin (main_window_gdk, &mwg_x, &mwg_y);
+
+  t_x = mwg_x + tree_allocation.x;
+  t_y = mwg_y + tree_allocation.y;
+  popup_x = t_x;
+  popup_y = t_y;
+
+  sel = gtk_tree_view_get_selection (tree);
+
+  rows = gtk_tree_selection_get_selected_rows (sel, NULL);
+
+  if (rows->data)
+  {
+    GdkRectangle r;
+    p = (GtkTreePath *) rows->data;
+    gtk_tree_view_get_cell_area (tree, p, NULL, &r);
+    popup_x += r.x;
+    popup_y += r.y;
+  }
+
+  g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
+  g_list_free (rows);
+  *x = popup_x;
+  *y = popup_y;
+  *push_in = FALSE;
+}
+
+static void
+do_metadata_popup_menu (GtkWidget *widget, GdkEventButton *event,
+    gpointer user_data)
+{
+  GtkMenu *menu;
+  GtkBuilder *builder;
+  int button, event_time;
+  GtkMenuPositionFunc mpf = NULL;
+
+  builder = GTK_BUILDER (user_data);
+
+  menu = GTK_MENU (gtk_builder_get_object (builder, "metadata_popup_menu"));
+
+  if (event)
+    {
+      button = event->button;
+      event_time = event->time;
+    }
+  else
+    {
+      button = 0;
+      event_time = gtk_get_current_event_time ();
+    }
+
+  gtk_menu_attach_to_widget (menu, widget, NULL);
+  gtk_menu_popup (menu, NULL, NULL, mpf, user_data, 
+                  button, event_time);
+}
+
+gboolean
+GNUNET_GTK_main_window_metadata_treeview_button_press_event_cb (GtkWidget *widget,
+    GdkEventButton *event, gpointer user_data)
+{
+ /* Ignore double-clicks and triple-clicks */
+  if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
+  {
+    do_metadata_popup_menu (widget, event, user_data);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+gboolean
+GNUNET_GTK_main_window_metadata_treeview_popup_menu_cb (GtkWidget *widget,
+    gpointer user_data)
+{
+  do_metadata_popup_menu (widget, NULL, user_data);
+  return TRUE;
+}
 
 
 /* end of gnunet-fs-gtk-event_handler.c */
diff --git a/src/fs/gnunet-fs-gtk.c b/src/fs/gnunet-fs-gtk.c
index e115395..dd4c951 100644
--- a/src/fs/gnunet-fs-gtk.c
+++ b/src/fs/gnunet-fs-gtk.c
@@ -572,6 +572,7 @@ GNUNET_GTK_main_window_realize_cb (GtkWidget *widget, gpointer user_data)
   GtkTreeStore *namespace_treestore;
   GtkBuilder *builder;
   GtkWidget *namespace_selector_window;
+  GtkTreeView *metadata_tree;
 
   builder = GTK_BUILDER (user_data);
 
@@ -579,6 +580,11 @@ GNUNET_GTK_main_window_realize_cb (GtkWidget *widget, gpointer user_data)
       ("main_window_search_namespace_treestore"));
   namespace_tree = GTK_TREE_VIEW (GNUNET_FS_GTK_get_main_window_object
       ("namespace_selector_treeview"));
+  metadata_tree = GTK_TREE_VIEW (GNUNET_FS_GTK_get_main_window_object
+      ("GNUNET_GTK_main_window_metadata_treeview"));
+
+  /* Allow multiple selection in metadata view */
+  gtk_tree_selection_set_mode (gtk_tree_view_get_selection (metadata_tree), GTK_SELECTION_MULTIPLE);
 
   /* FIXME: find a way to manage pseudonyms.
    * Right now the list will be filled with ALL and ANY pseudonyms that we
-- 
1.7.4

