diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-12-16 19:03:56 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-12-16 19:03:56 +0000 |
commit | 99c1933f1e99aa7da550e65082f80e73c9787f43 (patch) | |
tree | 03279c0ee7404e0cebf1b70cf25e5f0db491cbc8 | |
parent | 5dbb2088abda9734cea1cd9ffe817fdf901bc017 (diff) | |
download | gnunet-gtk-99c1933f1e99aa7da550e65082f80e73c9787f43.tar.gz gnunet-gtk-99c1933f1e99aa7da550e65082f80e73c9787f43.zip |
LRN: Make metadata list items selectable, make metadata copyable and be more careful with strings (validation) - #1759
-rw-r--r-- | contrib/gnunet_fs_gtk_main_window.glade | 18 | ||||
-rw-r--r-- | src/fs/gnunet-fs-gtk-common.c | 25 | ||||
-rw-r--r-- | src/fs/gnunet-fs-gtk-event_handler.c | 176 | ||||
-rw-r--r-- | src/fs/gnunet-fs-gtk.c | 6 |
4 files changed, 221 insertions, 4 deletions
diff --git a/contrib/gnunet_fs_gtk_main_window.glade b/contrib/gnunet_fs_gtk_main_window.glade index 37dab80d..a47a445c 100644 --- a/contrib/gnunet_fs_gtk_main_window.glade +++ b/contrib/gnunet_fs_gtk_main_window.glade | |||
@@ -602,7 +602,10 @@ | |||
602 | <property name="hadjustment">adjustment1</property> | 602 | <property name="hadjustment">adjustment1</property> |
603 | <property name="vadjustment">adjustment2</property> | 603 | <property name="vadjustment">adjustment2</property> |
604 | <property name="search_column">0</property> | 604 | <property name="search_column">0</property> |
605 | <property name="rubber_banding">True</property> | ||
605 | <property name="enable_grid_lines">both</property> | 606 | <property name="enable_grid_lines">both</property> |
607 | <signal name="button-press-event" handler="GNUNET_GTK_main_window_metadata_treeview_button_press_event_cb" swapped="no"/> | ||
608 | <signal name="popup-menu" handler="GNUNET_GTK_main_window_metadata_treeview_popup_menu_cb" swapped="no"/> | ||
606 | <child> | 609 | <child> |
607 | <object class="GtkTreeViewColumn" id="GNUNET_GTK_main_window_metadata_type_column"> | 610 | <object class="GtkTreeViewColumn" id="GNUNET_GTK_main_window_metadata_type_column"> |
608 | <property name="sizing">autosize</property> | 611 | <property name="sizing">autosize</property> |
@@ -628,7 +631,6 @@ | |||
628 | <property name="sort_indicator">True</property> | 631 | <property name="sort_indicator">True</property> |
629 | <child> | 632 | <child> |
630 | <object class="GtkCellRendererText" id="GNUNET_GTK_main_window_metadata_value_renderer"> | 633 | <object class="GtkCellRendererText" id="GNUNET_GTK_main_window_metadata_value_renderer"> |
631 | <property name="sensitive">False</property> | ||
632 | <property name="wrap_mode">word</property> | 634 | <property name="wrap_mode">word</property> |
633 | </object> | 635 | </object> |
634 | <attributes> | 636 | <attributes> |
@@ -849,6 +851,20 @@ | |||
849 | <column type="gchararray"/> | 851 | <column type="gchararray"/> |
850 | </columns> | 852 | </columns> |
851 | </object> | 853 | </object> |
854 | <object class="GtkMenu" id="metadata_popup_menu"> | ||
855 | <property name="visible">True</property> | ||
856 | <property name="can_focus">False</property> | ||
857 | <child> | ||
858 | <object class="GtkMenuItem" id="Copy selection"> | ||
859 | <property name="use_action_appearance">False</property> | ||
860 | <property name="visible">True</property> | ||
861 | <property name="can_focus">False</property> | ||
862 | <property name="label" translatable="yes">Copy selection</property> | ||
863 | <property name="use_underline">True</property> | ||
864 | <signal name="activate" handler="metadata_copy_selection_activated" swapped="no"/> | ||
865 | </object> | ||
866 | </child> | ||
867 | </object> | ||
852 | <object class="GtkWindow" id="namespace_selector_window"> | 868 | <object class="GtkWindow" id="namespace_selector_window"> |
853 | <property name="can_focus">False</property> | 869 | <property name="can_focus">False</property> |
854 | <property name="events">GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property> | 870 | <property name="events">GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property> |
diff --git a/src/fs/gnunet-fs-gtk-common.c b/src/fs/gnunet-fs-gtk-common.c index e7cb07f1..1a250c62 100644 --- a/src/fs/gnunet-fs-gtk-common.c +++ b/src/fs/gnunet-fs-gtk-common.c | |||
@@ -48,13 +48,32 @@ GNUNET_FS_GTK_add_meta_data_to_list_store (void *cls, const char *plugin_name, | |||
48 | const char *data_mime_type, | 48 | const char *data_mime_type, |
49 | const char *data, size_t data_len) | 49 | const char *data, size_t data_len) |
50 | { | 50 | { |
51 | gchar *data_to_insert = NULL; | ||
52 | gboolean freedata = FALSE; | ||
51 | GtkListStore *ls = GTK_LIST_STORE (cls); | 53 | GtkListStore *ls = GTK_LIST_STORE (cls); |
52 | 54 | ||
53 | if ((format == EXTRACTOR_METAFORMAT_UTF8) || | 55 | if (format == EXTRACTOR_METAFORMAT_UTF8) |
54 | (format == EXTRACTOR_METAFORMAT_C_STRING)) | 56 | { |
57 | if (g_utf8_validate (data, data_len, NULL)) | ||
58 | data_to_insert = data; | ||
59 | else | ||
60 | format = EXTRACTOR_METAFORMAT_C_STRING; | ||
61 | } | ||
62 | if (format == EXTRACTOR_METAFORMAT_C_STRING) | ||
63 | { | ||
64 | gsize rd, wr; | ||
65 | data_to_insert = g_locale_to_utf8 (data, data_len, &rd, &wr, NULL); | ||
66 | freedata = TRUE; | ||
67 | } | ||
68 | |||
69 | if (data_to_insert) | ||
70 | { | ||
55 | gtk_list_store_insert_with_values (ls, NULL, G_MAXINT, 0, type, 1, format, | 71 | gtk_list_store_insert_with_values (ls, NULL, G_MAXINT, 0, type, 1, format, |
56 | 2, EXTRACTOR_metatype_to_string (type), | 72 | 2, EXTRACTOR_metatype_to_string (type), |
57 | 3, data, -1); | 73 | 3, data_to_insert, -1); |
74 | if (freedata) | ||
75 | g_free (data_to_insert); | ||
76 | } | ||
58 | return 0; | 77 | return 0; |
59 | } | 78 | } |
60 | 79 | ||
diff --git a/src/fs/gnunet-fs-gtk-event_handler.c b/src/fs/gnunet-fs-gtk-event_handler.c index 74c3ab5d..8565bd05 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, | |||
1934 | gtk_list_store_clear (ms); | 1934 | gtk_list_store_clear (ms); |
1935 | } | 1935 | } |
1936 | 1936 | ||
1937 | static void | ||
1938 | copy_metadata_to_clipboard (GtkTreeModel *model, GtkTreePath *path, | ||
1939 | GtkTreeIter *iter, gpointer user_data) | ||
1940 | { | ||
1941 | gchar *type, *value; | ||
1942 | GList **l = (GList **) user_data; | ||
1943 | |||
1944 | gtk_tree_model_get (model, iter, 2, &type, 3, &value, -1); | ||
1945 | |||
1946 | *l = g_list_prepend (*l, type); | ||
1947 | *l = g_list_prepend (*l, value); | ||
1948 | } | ||
1949 | |||
1950 | void | ||
1951 | metadata_copy_selection_activated (GtkMenuItem *menuitem, gpointer user_data) | ||
1952 | { | ||
1953 | GtkBuilder *builder; | ||
1954 | GtkTreeView *tree; | ||
1955 | GtkClipboard *cb; | ||
1956 | GList *pairs = NULL, *l, *next, *value, *type; | ||
1957 | guint total_len; | ||
1958 | gchar *s, *p; | ||
1959 | |||
1960 | builder = GTK_BUILDER (user_data); | ||
1961 | tree = GTK_TREE_VIEW (gtk_builder_get_object (builder, | ||
1962 | "GNUNET_GTK_main_window_metadata_treeview")); | ||
1963 | |||
1964 | gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (tree), | ||
1965 | copy_metadata_to_clipboard, &pairs); | ||
1966 | |||
1967 | total_len = 0; | ||
1968 | pairs = g_list_reverse (pairs); | ||
1969 | for (l = pairs; l; l = next) | ||
1970 | { | ||
1971 | type = l; | ||
1972 | value = l->next; | ||
1973 | if (!value) | ||
1974 | break; | ||
1975 | next = value->next; | ||
1976 | total_len += strlen ((gchar *) type->data) | ||
1977 | + strlen ((gchar *) value->data) + 2 /* ": " */ + (next ? 1 : 0) /* "\n" */; | ||
1978 | } | ||
1979 | if (total_len > 0) | ||
1980 | { | ||
1981 | total_len += 1; /* "\0" */ | ||
1982 | s = g_new0 (gchar, total_len); | ||
1983 | p = s; | ||
1984 | for (l = pairs; l; l = next) | ||
1985 | { | ||
1986 | type = l; | ||
1987 | value = l->next; | ||
1988 | if (value) | ||
1989 | { | ||
1990 | next = value->next; | ||
1991 | p = g_stpcpy (p, (gchar *) type->data); | ||
1992 | p = g_stpcpy (p, ": "); | ||
1993 | p = g_stpcpy (p, (gchar *) value->data); | ||
1994 | if (next) | ||
1995 | p = g_stpcpy (p, "\n"); | ||
1996 | } | ||
1997 | else | ||
1998 | next = NULL; | ||
1999 | } | ||
2000 | } | ||
2001 | g_list_foreach (pairs, (GFunc) g_free, NULL); | ||
2002 | g_list_free (pairs); | ||
2003 | pairs = NULL; | ||
2004 | |||
2005 | if (total_len > 0) | ||
2006 | { | ||
2007 | cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); | ||
2008 | gtk_clipboard_set_text (cb, s, -1); | ||
2009 | gtk_clipboard_store (cb); | ||
2010 | g_free (s); | ||
2011 | } | ||
2012 | } | ||
2013 | |||
2014 | void | ||
2015 | metadata_menu_popup_position (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, | ||
2016 | gpointer user_data) | ||
2017 | { | ||
2018 | GtkBuilder *builder; | ||
2019 | GtkTreeView *tree; | ||
2020 | GtkTreeSelection *sel; | ||
2021 | GList *rows; | ||
2022 | GtkTreePath *p; | ||
2023 | GtkAllocation tree_allocation; | ||
2024 | GdkWindow *main_window_gdk; | ||
2025 | gint mwg_x, mwg_y, t_x, t_y, popup_x, popup_y; | ||
2026 | |||
2027 | builder = GTK_BUILDER (user_data); | ||
2028 | |||
2029 | tree = GTK_TREE_VIEW (gtk_builder_get_object (builder, | ||
2030 | "GNUNET_GTK_main_window_metadata_treeview")); | ||
2031 | |||
2032 | gtk_widget_get_allocation (GTK_WIDGET (tree), &tree_allocation); | ||
2033 | |||
2034 | main_window_gdk = gtk_widget_get_window (GTK_WIDGET (tree)); | ||
2035 | |||
2036 | gdk_window_get_origin (main_window_gdk, &mwg_x, &mwg_y); | ||
2037 | |||
2038 | t_x = mwg_x + tree_allocation.x; | ||
2039 | t_y = mwg_y + tree_allocation.y; | ||
2040 | popup_x = t_x; | ||
2041 | popup_y = t_y; | ||
2042 | |||
2043 | sel = gtk_tree_view_get_selection (tree); | ||
2044 | |||
2045 | rows = gtk_tree_selection_get_selected_rows (sel, NULL); | ||
2046 | |||
2047 | if (rows->data) | ||
2048 | { | ||
2049 | GdkRectangle r; | ||
2050 | p = (GtkTreePath *) rows->data; | ||
2051 | gtk_tree_view_get_cell_area (tree, p, NULL, &r); | ||
2052 | popup_x += r.x; | ||
2053 | popup_y += r.y; | ||
2054 | } | ||
2055 | |||
2056 | g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL); | ||
2057 | g_list_free (rows); | ||
2058 | *x = popup_x; | ||
2059 | *y = popup_y; | ||
2060 | *push_in = FALSE; | ||
2061 | } | ||
2062 | |||
2063 | static void | ||
2064 | do_metadata_popup_menu (GtkWidget *widget, GdkEventButton *event, | ||
2065 | gpointer user_data) | ||
2066 | { | ||
2067 | GtkMenu *menu; | ||
2068 | GtkBuilder *builder; | ||
2069 | int button, event_time; | ||
2070 | GtkMenuPositionFunc mpf = NULL; | ||
2071 | |||
2072 | builder = GTK_BUILDER (user_data); | ||
2073 | |||
2074 | menu = GTK_MENU (gtk_builder_get_object (builder, "metadata_popup_menu")); | ||
2075 | |||
2076 | if (event) | ||
2077 | { | ||
2078 | button = event->button; | ||
2079 | event_time = event->time; | ||
2080 | } | ||
2081 | else | ||
2082 | { | ||
2083 | button = 0; | ||
2084 | event_time = gtk_get_current_event_time (); | ||
2085 | } | ||
2086 | |||
2087 | gtk_menu_attach_to_widget (menu, widget, NULL); | ||
2088 | gtk_menu_popup (menu, NULL, NULL, mpf, user_data, | ||
2089 | button, event_time); | ||
2090 | } | ||
2091 | |||
2092 | gboolean | ||
2093 | GNUNET_GTK_main_window_metadata_treeview_button_press_event_cb (GtkWidget *widget, | ||
2094 | GdkEventButton *event, gpointer user_data) | ||
2095 | { | ||
2096 | /* Ignore double-clicks and triple-clicks */ | ||
2097 | if (event->button == 3 && event->type == GDK_BUTTON_PRESS) | ||
2098 | { | ||
2099 | do_metadata_popup_menu (widget, event, user_data); | ||
2100 | return TRUE; | ||
2101 | } | ||
2102 | |||
2103 | return FALSE; | ||
2104 | } | ||
2105 | |||
2106 | gboolean | ||
2107 | GNUNET_GTK_main_window_metadata_treeview_popup_menu_cb (GtkWidget *widget, | ||
2108 | gpointer user_data) | ||
2109 | { | ||
2110 | do_metadata_popup_menu (widget, NULL, user_data); | ||
2111 | return TRUE; | ||
2112 | } | ||
1937 | 2113 | ||
1938 | 2114 | ||
1939 | /* end of gnunet-fs-gtk-event_handler.c */ | 2115 | /* 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 e115395c..dd4c9512 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) | |||
572 | GtkTreeStore *namespace_treestore; | 572 | GtkTreeStore *namespace_treestore; |
573 | GtkBuilder *builder; | 573 | GtkBuilder *builder; |
574 | GtkWidget *namespace_selector_window; | 574 | GtkWidget *namespace_selector_window; |
575 | GtkTreeView *metadata_tree; | ||
575 | 576 | ||
576 | builder = GTK_BUILDER (user_data); | 577 | builder = GTK_BUILDER (user_data); |
577 | 578 | ||
@@ -579,6 +580,11 @@ GNUNET_GTK_main_window_realize_cb (GtkWidget *widget, gpointer user_data) | |||
579 | ("main_window_search_namespace_treestore")); | 580 | ("main_window_search_namespace_treestore")); |
580 | namespace_tree = GTK_TREE_VIEW (GNUNET_FS_GTK_get_main_window_object | 581 | namespace_tree = GTK_TREE_VIEW (GNUNET_FS_GTK_get_main_window_object |
581 | ("namespace_selector_treeview")); | 582 | ("namespace_selector_treeview")); |
583 | metadata_tree = GTK_TREE_VIEW (GNUNET_FS_GTK_get_main_window_object | ||
584 | ("GNUNET_GTK_main_window_metadata_treeview")); | ||
585 | |||
586 | /* Allow multiple selection in metadata view */ | ||
587 | gtk_tree_selection_set_mode (gtk_tree_view_get_selection (metadata_tree), GTK_SELECTION_MULTIPLE); | ||
582 | 588 | ||
583 | /* FIXME: find a way to manage pseudonyms. | 589 | /* FIXME: find a way to manage pseudonyms. |
584 | * Right now the list will be filled with ALL and ANY pseudonyms that we | 590 | * Right now the list will be filled with ALL and ANY pseudonyms that we |