aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-01-31 22:54:08 +0000
committerChristian Grothoff <christian@grothoff.org>2012-01-31 22:54:08 +0000
commitd5d5c6af38d38b0d7ffd1b6c4bdbbdfa28f27fb0 (patch)
treef5e1a4381388bf239c363fe491fea77c775e2020
parente80931502cecf89cec2926f3750f45149a57bec2 (diff)
downloadgnunet-gtk-d5d5c6af38d38b0d7ffd1b6c4bdbbdfa28f27fb0.tar.gz
gnunet-gtk-d5d5c6af38d38b0d7ffd1b6c4bdbbdfa28f27fb0.zip
-cleaning up meta data context menu code and moving to its own file
-rw-r--r--src/fs/Makefile.am1
-rw-r--r--src/fs/gnunet-fs-gtk-download.c10
-rw-r--r--src/fs/gnunet-fs-gtk-event_handler.c1053
-rw-r--r--src/fs/gnunet-fs-gtk-main_window_meta_data_context_menu.c192
4 files changed, 674 insertions, 582 deletions
diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am
index 574a260c..6fe1c6e1 100644
--- a/src/fs/Makefile.am
+++ b/src/fs/Makefile.am
@@ -16,6 +16,7 @@ gnunet_fs_gtk_SOURCES = \
16 gnunet-fs-gtk-edit_publish_dialog.c gnunet-fs-gtk-edit_publish_dialog.h \ 16 gnunet-fs-gtk-edit_publish_dialog.c gnunet-fs-gtk-edit_publish_dialog.h \
17 gnunet-fs-gtk-event_handler.c gnunet-fs-gtk-event_handler.h \ 17 gnunet-fs-gtk-event_handler.c gnunet-fs-gtk-event_handler.h \
18 gnunet-fs-gtk-anonymity_spin_buttons.c \ 18 gnunet-fs-gtk-anonymity_spin_buttons.c \
19 gnunet-fs-gtk-main_window_meta_data_context_menu.c \
19 gnunet-fs-gtk.c gnunet-fs-gtk.h \ 20 gnunet-fs-gtk.c gnunet-fs-gtk.h \
20 gnunet-fs-gtk-main_window_create_pseudonym.c \ 21 gnunet-fs-gtk-main_window_create_pseudonym.c \
21 gnunet-fs-gtk-main_window_file_download.c \ 22 gnunet-fs-gtk-main_window_file_download.c \
diff --git a/src/fs/gnunet-fs-gtk-download.c b/src/fs/gnunet-fs-gtk-download.c
index 8781de8b..cba115ab 100644
--- a/src/fs/gnunet-fs-gtk-download.c
+++ b/src/fs/gnunet-fs-gtk-download.c
@@ -232,11 +232,6 @@ GNUNET_FS_GTK_download_context_start_download (struct DownloadContext *dc)
232 GtkTreeIter iter; 232 GtkTreeIter iter;
233 GtkTreePath *path; 233 GtkTreePath *path;
234 234
235 fs = GNUNET_FS_GTK_get_fs_handle ();
236 opt = GNUNET_FS_DOWNLOAD_OPTION_NONE;
237 if (dc->is_recursive)
238 opt |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE;
239 len = GNUNET_FS_uri_chk_get_file_size (dc->uri);
240 de = GNUNET_malloc (sizeof (struct DownloadEntry)); 235 de = GNUNET_malloc (sizeof (struct DownloadEntry));
241 de->uri = dc->uri; 236 de->uri = dc->uri;
242 dc->uri = NULL; 237 dc->uri = NULL;
@@ -268,6 +263,11 @@ GNUNET_FS_GTK_download_context_start_download (struct DownloadContext *dc)
268 if (NULL != path) 263 if (NULL != path)
269 gtk_tree_path_free (path); 264 gtk_tree_path_free (path);
270 } 265 }
266 fs = GNUNET_FS_GTK_get_fs_handle ();
267 opt = GNUNET_FS_DOWNLOAD_OPTION_NONE;
268 if (dc->is_recursive)
269 opt |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE;
270 len = GNUNET_FS_uri_chk_get_file_size (dc->uri);
271 if (dc->sr != NULL) 271 if (dc->sr != NULL)
272 { 272 {
273 GNUNET_break (NULL != 273 GNUNET_break (NULL !=
diff --git a/src/fs/gnunet-fs-gtk-event_handler.c b/src/fs/gnunet-fs-gtk-event_handler.c
index 8320c8bf..d9b4dab8 100644
--- a/src/fs/gnunet-fs-gtk-event_handler.c
+++ b/src/fs/gnunet-fs-gtk-event_handler.c
@@ -28,12 +28,11 @@
28#include "gnunet-fs-gtk-event_handler.h" 28#include "gnunet-fs-gtk-event_handler.h"
29#include <string.h> 29#include <string.h>
30 30
31static struct SearchTab *search_tab_head;
32
33static struct SearchTab *search_tab_tail;
34
35static struct SearchTab *uri_tab;
36 31
32/**
33 * We have a single tab where we display publishing operations.
34 * So there is only one instance of this struct.
35 */
37struct PublishTab 36struct PublishTab
38{ 37{
39 38
@@ -54,6 +53,11 @@ struct PublishTab
54}; 53};
55 54
56 55
56/**
57 * Information we keep for each file or directory being published.
58 * Used to quickly identify the tab and row of the operation; stored
59 * in the user-context of the FS library for the publish operation.
60 */
57struct PublishEntry 61struct PublishEntry
58{ 62{
59 /** 63 /**
@@ -76,10 +80,19 @@ struct PublishEntry
76 */ 80 */
77 struct GNUNET_FS_Uri *uri; 81 struct GNUNET_FS_Uri *uri;
78 82
83 /**
84 * Is this the top-level entry for the publish operation
85 * or sub-operation?
86 */
79 int is_top; 87 int is_top;
80}; 88};
81 89
82 90
91/**
92 * Information we keep for each search result. Used to quickly
93 * identify the tab and row of the result; stored in the user-context
94 * of the FS library for the search result.
95 */
83struct SearchResult 96struct SearchResult
84{ 97{
85 /** 98 /**
@@ -105,48 +118,450 @@ struct SearchResult
105}; 118};
106 119
107 120
108struct StartDownloadContext
109{
110 struct SearchTab *tab;
111 gboolean recursive;
112};
113 121
122/**
123 * Head of linked list of tabs for searches.
124 */
125static struct SearchTab *search_tab_head;
126
127/**
128 * Tail of linked list of tabs for searches.
129 */
130static struct SearchTab *search_tab_tail;
131
132/**
133 * Special tab we use to for downloads-by-URIs and downloads
134 * where the search tab has been closed ("parent lost").
135 */
136static struct SearchTab *uri_tab;
137
138/**
139 * Special tab we use to store publishing operations.
140 */
114static struct PublishTab *publish_tab; 141static struct PublishTab *publish_tab;
115 142
116/** 143/**
117 * Row reference for the current search context menu. 144 * Row reference for the current search context menu.
145 * FIXME: de-globalize?
118 */ 146 */
119static GtkTreeRowReference *current_context_row_reference; 147static GtkTreeRowReference *current_context_row_reference;
120 148
121/** 149/**
122 * Search tab used for the current search context menu. 150 * Search tab used for the current search context menu.
151 * FIXME: de-globalize?
123 */ 152 */
124static struct SearchTab *current_context_search_tab; 153static struct SearchTab *current_context_search_tab;
125 154
126static void
127start_download_ctx_menu (GtkMenuItem *item, gpointer user_data);
128 155
156
157/**
158 * Closure for the 'start_download' callback.
159 */
160struct StartDownloadContext
161{
162 /**
163 * Search tab to search for the request.
164 */
165 struct SearchTab *tab;
166
167 /**
168 * Was the 'recursive' option requested?
169 */
170 gboolean recursive;
171
172};
173
174
175/**
176 * This should get the default download directory (so that GNUnet
177 * won't offer the user to download files to the 'bin' subdirectory,
178 * or whatever is the cwd). Returns NULL on failure (such as
179 * non-existend directory). Should also preserve the last setting (so
180 * if the user saves files somewhere else, next time we default to
181 * somewhere else, at least until application restart, or maybe even
182 * between application restarts).
183 *
184 * Fills the @buffer up to @size bytes, returns a pointer to it.
185 */
186static char *
187get_default_download_directory (char *buffer, size_t size)
188{
189 return NULL;
190}
191
192
193/**
194 * Called recursively to build a suggested filename by prepending
195 * suggested names for its parent directories (if any).
196 *
197 * @param tm FIXME
198 * @param iter FIXME
199 * @param top FIXME
200 * @param local_parents set to GNUNET_YES if all parents are directories, and are downloaded.
201 * @param anonymity FIXME
202 * @param filename_is_absolute FIXME
203 * @return suggested filename, possibly NULL
204 */
205static char *
206get_suggested_filename_anonymity (GtkTreeModel *tm,
207 GtkTreeIter *iter,
208 int top,
209 int *local_parents,
210 int *anonymity,
211 int *filename_is_absolute)
212{
213 char *result;
214 char *dirname;
215 char *local_filename, *filename;
216 int downloaded_anonymity;
217 int have_a_parent;
218 struct GNUNET_CONTAINER_MetaData *meta;
219 GtkTreeIter parent;
220 gtk_tree_model_get (tm, iter, 0, &meta, 15, &local_filename, 16, &downloaded_anonymity, -1);
221 if (local_filename == NULL && !top)
222 *local_parents = GNUNET_NO;
223 if (downloaded_anonymity != -1 && *anonymity == -1 && !top)
224 *anonymity = downloaded_anonymity;
225 if (gtk_tree_model_iter_parent (tm, &parent, iter))
226 {
227 have_a_parent = GNUNET_YES;
228 dirname = get_suggested_filename_anonymity (tm, &parent, GNUNET_NO, local_parents, anonymity, filename_is_absolute);
229 }
230 else
231 {
232 have_a_parent = GNUNET_NO;
233 dirname = NULL;
234 if (top)
235 *local_parents = GNUNET_NO;
236 }
237 if (local_filename == NULL)
238 filename = GNUNET_FS_meta_data_suggest_filename (meta);
239 else
240 {
241 /* This directory was downloaded as /foo/bar/baz/somedirname
242 * Hopefully, "somedirname" is actually "somedir.gnd"
243 * We need to strip the ".gnd" part to get "somedir", which is
244 * what we're going to use instead of suggested original filename
245 * Without the .gnd extension we're going to just use a copy
246 * of the directory file name - and that would fail. Sad.
247 */
248 const char *basename;
249 if (dirname == NULL && !have_a_parent)
250 {
251 /* This is the ealderlest parent directory. Use absolute path. */
252 basename = (const char *) local_filename;
253 *filename_is_absolute = GNUNET_YES;
254 }
255 else
256 basename = GNUNET_STRINGS_get_short_name (local_filename);
257 if (basename != NULL && strlen (basename) > 0)
258 {
259 char *dot;
260 filename = GNUNET_strdup (basename);
261 dot = strrchr (filename, '.');
262 if (dot)
263 *dot = '\0';
264 }
265 else
266 filename = GNUNET_FS_meta_data_suggest_filename (meta);
267 }
268 if (dirname && filename)
269 {
270 GNUNET_asprintf (&result, "%s%s%s", dirname, DIR_SEPARATOR_STR, filename);
271 GNUNET_free (filename);
272 GNUNET_free (dirname);
273 return result;
274 }
275 else if (filename)
276 return filename;
277 else
278 return NULL;
279}
280
281
282/**
283 * This function is called when the user double-clicks on a search
284 * result. Begins the download, if necessary by opening the "save as"
285 * window.
286 *
287 * @param tree_view tree view with the details
288 * @param path path selecting which entry we want to download
289 * @param column unused entry specifying which column the mouse was in
290 * @param user_data a 'struct StartDownloadContext' with additional details
291 */
129static void 292static void
130start_download_recursively_ctx_menu (GtkMenuItem *item, gpointer user_data); 293start_download (GtkTreeView * tree_view, GtkTreePath * path,
294 GtkTreeViewColumn * column, gpointer user_data)
295{
296 struct StartDownloadContext *sdc = user_data;
297 struct SearchTab *tab = sdc->tab;
298 GtkTreeModel *tm;
299 GtkTreeIter iter;
300 struct GNUNET_FS_Uri *uri;
301 struct GNUNET_CONTAINER_MetaData *meta;
302 struct SearchResult *sr;
303 gchar *mime;
304 struct DownloadContext *dc;
305 char *buf = NULL;
306 char *tmp;
307 size_t tmplen;
308 char cwd[FILENAME_MAX];
309 char *download_directory;
310 char *filename;
311 int local_parents;
312 int have_a_suggestion;
313 int anonymity;
314 int filename_is_absolute;
315
316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317 "Starting a %sdownload\n",
318 sdc->recursive ? "recursive " : "");
319
320 GNUNET_assert (tab != NULL);
321 tm = gtk_tree_view_get_model (tree_view);
322 if (TRUE != gtk_tree_model_get_iter (tm, &iter, path))
323 {
324 GNUNET_break (0);
325 // FIXME: this is bad...
326 GNUNET_free (sdc);
327 return;
328 }
329 gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, 9, &sr, 10, &mime, -1);
330 if (NULL == uri)
331 {
332 /* user clicked on directory that was opened (not downloaded!), so we
333 have no URI and downloading makes no sense. Ignore! */
334 if (NULL != mime)
335 g_free (mime);
336 return;
337 }
338 if (!(GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri)))
339 {
340 /* can only download chk/loc URIs, ignore */
341 g_free (mime);
342 return;
343 }
131 344
345 download_directory = get_default_download_directory (cwd, sizeof (cwd));
346 /* If no download directory is known, try working directory */
347 if (download_directory == NULL)
348 download_directory = getcwd (cwd, sizeof (cwd));
349 /* Calculate suggested filename */
350 local_parents = GNUNET_YES;
351 anonymity = -1;
352 filename_is_absolute = GNUNET_NO;
353 filename = get_suggested_filename_anonymity (tm, &iter, GNUNET_YES, &local_parents, &anonymity, &filename_is_absolute);
354 have_a_suggestion = GNUNET_NO;
355 if (NULL != download_directory)
356 {
357 if (NULL == filename)
358 {
359 buf = GNUNET_strdup (download_directory);
360 }
361 else
362 {
363 have_a_suggestion = GNUNET_YES;
364 if (filename_is_absolute)
365 GNUNET_asprintf (&tmp, "%s", filename);
366 else
367 GNUNET_asprintf (&tmp, "%s%s%s",
368 download_directory,
369 DIR_SEPARATOR_STR,
370 filename);
371 tmplen = strlen (tmp);
372 /* now, if we have a directory, replace trailing '/' with ".gnd" */
373 if (GNUNET_YES ==
374 GNUNET_FS_meta_data_test_for_directory (meta))
375 {
376 if ( (tmp[tmplen-1] == '/') ||
377 (tmp[tmplen-1] == '\\') )
378 tmp[tmplen-1] = '\0';
379 GNUNET_asprintf (&buf,
380 "%s%s",
381 tmp,
382 GNUNET_FS_DIRECTORY_EXT);
383 GNUNET_free (tmp);
384 }
385 else
386 {
387 buf = tmp;
388 }
389 }
390 }
391 GNUNET_free_non_null (filename);
392
393 /* now setup everything for the save-as dialog */
394 dc = GNUNET_malloc (sizeof (struct DownloadContext));
395 dc->uri = GNUNET_FS_uri_dup (uri);
396 dc->mime = mime;
397 dc->filename = buf;
398 dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
399 dc->rr = gtk_tree_row_reference_new (tm, path);
400 dc->sr = sr->result;
401 dc->anonymity = anonymity;
402 dc->is_recursive = sdc->recursive;
403 dc->tab = tab;
404 if (local_parents && have_a_suggestion)
405 /* Skip the dialog, call directly */
406 GNUNET_FS_GTK_download_context_start_download (dc);
407 else
408 GNUNET_FS_GTK_open_download_as_dialog (dc);
409}
410
411
412/**
413 * An item was selected from the context menu; destroy
414 * the menu shell.
415 *
416 * @param menushell menu to destroy
417 * @parma user_data the 'struct DownloadEntry' for the menu (unused)
418 */
132static void 419static void
133abort_download_ctx_menu (GtkMenuItem *item, gpointer user_data); 420search_list_popup_selection_done (GtkMenuShell *menushell,
421 gpointer user_data)
422{
423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424 "Item selected in menu shell %p, destroying it.\n",
425 menushell);
426 gtk_widget_destroy (GTK_WIDGET (menushell));
427}
134 428
429
430/**
431 * "Download" was selected in the current search context menu.
432 *
433 * @param item the 'download' menu item
434 * @parma user_data the 'struct DownloadEntry' to download.
435 */
135static void 436static void
136copy_uri_to_clipboard_ctx_menu (GtkMenuItem *item, gpointer user_data); 437start_download_ctx_menu (GtkMenuItem *item, gpointer user_data)
438{
439 GtkTreePath *path;
440 GtkTreeView *tv;
441 struct StartDownloadContext sdc;
442
443 if (current_context_row_reference == NULL)
444 {
445 GNUNET_break (0);
446 return;
447 }
448 path = gtk_tree_row_reference_get_path (current_context_row_reference);
449 gtk_tree_row_reference_free (current_context_row_reference);
450 current_context_row_reference = NULL;
451 tv = GTK_TREE_VIEW (gtk_builder_get_object
452 (current_context_search_tab->builder,
453 "_search_result_frame"));
454 sdc.tab = current_context_search_tab;
455 sdc.recursive = FALSE;
456 start_download (tv, path, NULL, &sdc);
457 gtk_tree_path_free (path);
458 current_context_search_tab = NULL;
459}
460
137 461
462/**
463 * "Download recursively" was selected in the current search context menu.
464 *
465 * @param item the 'download recursively' menu item
466 * @parma user_data the 'struct DownloadEntry' to download.
467 */
138static void 468static void
139free_search_result (struct SearchResult *sr); 469start_download_recursively_ctx_menu (GtkMenuItem *item, gpointer user_data)
470{
471 GtkTreePath *path;
472 GtkTreeView *tv;
473 struct StartDownloadContext sdc;
140 474
141void 475 if (current_context_row_reference == NULL)
142search_list_popup_selection_done (GtkMenuShell *menushell, 476 {
143 gpointer user_data) 477 GNUNET_break (0);
478 return;
479 }
480 path = gtk_tree_row_reference_get_path (current_context_row_reference);
481 gtk_tree_row_reference_free (current_context_row_reference);
482 current_context_row_reference = NULL;
483 tv = GTK_TREE_VIEW (gtk_builder_get_object
484 (current_context_search_tab->builder,
485 "_search_result_frame"));
486 sdc.tab = current_context_search_tab;
487 sdc.recursive = TRUE;
488 start_download (tv, path, NULL, &sdc);
489 gtk_tree_path_free (path);
490 current_context_search_tab = NULL;
491}
492
493
494/**
495 * Download "abort" was selected in the current search context menu.
496 *
497 * @param item the 'abort' menu item
498 * @parma user_data the 'struct DownloadEntry' to abort.
499 */
500static void
501abort_download_ctx_menu (GtkMenuItem *item, gpointer user_data)
144{ 502{
503 struct DownloadEntry *de = user_data;
504
145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146 "Item selected in menu shell %x\n", menushell); 506 "Aborting download DE=%p\n",
147 gtk_widget_destroy (GTK_WIDGET (menushell)); 507 de);
508 GNUNET_assert (de->dc != NULL);
509 GNUNET_FS_download_stop (de->dc, GNUNET_YES);
510 current_context_search_tab = NULL;
148} 511}
149 512
513
514/**
515 * Copy current URI to clipboard.
516 *
517 * @param item the 'copy-to-clipboard' menu item
518 * @parma user_data the 'struct DownloadEntry' to copy from
519 */
520static void
521copy_uri_to_clipboard_ctx_menu (GtkMenuItem *item, gpointer user_data)
522{
523 GtkTreePath *path;
524 GtkTreeView *tv;
525 GtkTreeModel *tm;
526 GtkTreeIter iter;
527 struct GNUNET_FS_Uri *uri;
528 char *uris;
529 GtkClipboard *cb;
530
531 if (current_context_row_reference == NULL)
532 {
533 GNUNET_break (0);
534 return;
535 }
536 path = gtk_tree_row_reference_get_path (current_context_row_reference);
537 gtk_tree_row_reference_free (current_context_row_reference);
538 current_context_row_reference = NULL;
539 tv = GTK_TREE_VIEW (gtk_builder_get_object
540 (current_context_search_tab->builder,
541 "_search_result_frame"));
542 tm = gtk_tree_view_get_model (tv);
543 if (TRUE != gtk_tree_model_get_iter (tm, &iter, path))
544 {
545 GNUNET_break (0);
546 gtk_tree_path_free (path);
547 return;
548 }
549 gtk_tree_model_get (tm, &iter, 1, &uri, -1);
550 gtk_tree_path_free (path);
551 current_context_search_tab = NULL;
552 if (uri == NULL)
553 {
554 GNUNET_break (0);
555 return;
556 }
557 uris = GNUNET_FS_uri_to_string (uri);
558 cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
559 gtk_clipboard_set_text (cb, uris, -1);
560 gtk_clipboard_store (cb);
561 GNUNET_free (uris);
562}
563
564
150static gboolean 565static gboolean
151search_list_popup (GtkTreeView *tv, struct SearchTab *tab, GdkEventButton *event_button) 566search_list_popup (GtkTreeView *tv, struct SearchTab *tab, GdkEventButton *event_button)
152{ 567{
@@ -813,345 +1228,9 @@ setup_download (struct DownloadEntry *de, struct DownloadEntry *pde,
813 return de; 1228 return de;
814} 1229}
815 1230
816/**
817 * This should get the default download directory
818 * (so that GNUnet won't offer the user to download files
819 * to the 'bin' subdirectory, or whatever is the cwd).
820 * Returns NULL on failure (such as non-existend directory).
821 * Should also preserve the last setting (so if the user
822 * saves files somewhere else, next time we default to
823 * somewhere else, at least until application restart, or maybe even
824 * between application restarts).
825 * Fills the @buffer up to @size bytes, returns a pointer to it.
826 */
827static char *
828get_default_download_directory (char *buffer, size_t size)
829{
830 return NULL;
831}
832
833/**
834 * Called recursively to build a suggested filename by
835 * prepending suggested names for its parent directories (if any).
836 * Might return NULL. Returned name might be absolute.
837 * local_parents is set to GNUNET_YES if all parents are directories,
838 * and are downloaded.
839 */
840static char *
841get_suggested_filename_anonymity (GtkTreeModel *tm, GtkTreeIter *iter, int top,
842 int *local_parents, int *anonymity, int *filename_is_absolute)
843{
844 char *result;
845 char *dirname;
846 char *local_filename, *filename;
847 int downloaded_anonymity;
848 int have_a_parent;
849 struct GNUNET_CONTAINER_MetaData *meta;
850 GtkTreeIter parent;
851 gtk_tree_model_get (tm, iter, 0, &meta, 15, &local_filename, 16, &downloaded_anonymity, -1);
852 if (local_filename == NULL && !top)
853 *local_parents = GNUNET_NO;
854 if (downloaded_anonymity != -1 && *anonymity == -1 && !top)
855 *anonymity = downloaded_anonymity;
856 if (gtk_tree_model_iter_parent (tm, &parent, iter))
857 {
858 have_a_parent = GNUNET_YES;
859 dirname = get_suggested_filename_anonymity (tm, &parent, GNUNET_NO, local_parents, anonymity, filename_is_absolute);
860 }
861 else
862 {
863 have_a_parent = GNUNET_NO;
864 dirname = NULL;
865 if (top)
866 *local_parents = GNUNET_NO;
867 }
868 if (local_filename == NULL)
869 filename = GNUNET_FS_meta_data_suggest_filename (meta);
870 else
871 {
872 /* This directory was downloaded as /foo/bar/baz/somedirname
873 * Hopefully, "somedirname" is actually "somedir.gnd"
874 * We need to strip the ".gnd" part to get "somedir", which is
875 * what we're going to use instead of suggested original filename
876 * Without the .gnd extension we're going to just use a copy
877 * of the directory file name - and that would fail. Sad.
878 */
879 const char *basename;
880 if (dirname == NULL && !have_a_parent)
881 {
882 /* This is the ealderlest parent directory. Use absolute path. */
883 basename = (const char *) local_filename;
884 *filename_is_absolute = GNUNET_YES;
885 }
886 else
887 basename = GNUNET_STRINGS_get_short_name (local_filename);
888 if (basename != NULL && strlen (basename) > 0)
889 {
890 char *dot;
891 filename = GNUNET_strdup (basename);
892 dot = strrchr (filename, '.');
893 if (dot)
894 *dot = '\0';
895 }
896 else
897 filename = GNUNET_FS_meta_data_suggest_filename (meta);
898 }
899 if (dirname && filename)
900 {
901 GNUNET_asprintf (&result, "%s%s%s", dirname, DIR_SEPARATOR_STR, filename);
902 GNUNET_free (filename);
903 GNUNET_free (dirname);
904 return result;
905 }
906 else if (filename)
907 return filename;
908 else
909 return NULL;
910}
911
912/**
913 * Tell FS to start a download. Begins by opening the
914 * "save as" window.
915 */
916static void
917start_download (GtkTreeView * tree_view, GtkTreePath * path,
918 GtkTreeViewColumn * column, gpointer user_data)
919{
920 struct StartDownloadContext *sdc = user_data;
921 struct SearchTab *tab = sdc->tab;
922 GtkTreeModel *tm;
923 GtkTreeIter iter;
924 struct GNUNET_FS_Uri *uri;
925 struct GNUNET_CONTAINER_MetaData *meta;
926 struct SearchResult *sr;
927 gchar *mime;
928 struct DownloadContext *dc;
929 char *buf = NULL;
930 char *tmp;
931 size_t tmplen;
932 char cwd[FILENAME_MAX];
933 char *download_directory;
934 char *filename;
935 int local_parents;
936 int have_a_suggestion;
937 int anonymity;
938 int filename_is_absolute;
939
940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
941 "Starting a %sdownload\n", sdc->recursive ? "recursive " : "");
942
943 GNUNET_assert (tab != NULL);
944 tm = gtk_tree_view_get_model (tree_view);
945 if (TRUE != gtk_tree_model_get_iter (tm, &iter, path))
946 {
947 GNUNET_break (0);
948 GNUNET_free (sdc);
949 return;
950 }
951 gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, 9, &sr, 10, &mime, -1);
952 if (NULL == uri)
953 {
954 /* user clicked on directory that was opened (not downloaded!), so we
955 have no URI and downloading makes no sense. Ignore! */
956 if (NULL != mime)
957 g_free (mime);
958 return;
959 }
960 if (!(GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri)))
961 {
962 /* can only download chk/loc URIs, ignore */
963 g_free (mime);
964 return;
965 }
966
967 download_directory = get_default_download_directory (cwd, sizeof (cwd));
968 /* If no download directory is known, try working directory */
969 if (download_directory == NULL)
970 download_directory = getcwd (cwd, sizeof (cwd));
971 /* Calculate suggested filename */
972 local_parents = GNUNET_YES;
973 anonymity = -1;
974 filename_is_absolute = GNUNET_NO;
975 filename = get_suggested_filename_anonymity (tm, &iter, GNUNET_YES, &local_parents, &anonymity, &filename_is_absolute);
976 have_a_suggestion = GNUNET_NO;
977 if (NULL != download_directory)
978 {
979 if (NULL == filename)
980 {
981 buf = GNUNET_strdup (download_directory);
982 }
983 else
984 {
985 have_a_suggestion = GNUNET_YES;
986 if (filename_is_absolute)
987 GNUNET_asprintf (&tmp, "%s", filename);
988 else
989 GNUNET_asprintf (&tmp, "%s%s%s",
990 download_directory,
991 DIR_SEPARATOR_STR,
992 filename);
993 tmplen = strlen (tmp);
994 /* now, if we have a directory, replace trailing '/' with ".gnd" */
995 if (GNUNET_YES ==
996 GNUNET_FS_meta_data_test_for_directory (meta))
997 {
998 if ( (tmp[tmplen-1] == '/') ||
999 (tmp[tmplen-1] == '\\') )
1000 tmp[tmplen-1] = '\0';
1001 GNUNET_asprintf (&buf,
1002 "%s%s",
1003 tmp,
1004 GNUNET_FS_DIRECTORY_EXT);
1005 GNUNET_free (tmp);
1006 }
1007 else
1008 {
1009 buf = tmp;
1010 }
1011 }
1012 }
1013 GNUNET_free_non_null (filename);
1014
1015 /* now setup everything for the save-as dialog */
1016 dc = GNUNET_malloc (sizeof (struct DownloadContext));
1017 dc->uri = GNUNET_FS_uri_dup (uri);
1018 dc->mime = mime;
1019 dc->filename = buf;
1020 dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
1021 dc->rr = gtk_tree_row_reference_new (tm, path);
1022 dc->sr = sr->result;
1023 dc->anonymity = anonymity;
1024 dc->is_recursive = sdc->recursive;
1025 dc->tab = tab;
1026 if (local_parents && have_a_suggestion)
1027 /* Skip the dialog, call directly */
1028 GNUNET_FS_GTK_download_context_start_download (dc);
1029 else
1030 GNUNET_FS_GTK_open_download_as_dialog (dc);
1031}
1032
1033
1034
1035/**
1036 * "Download" was selected in the current search context menu.
1037 */
1038static void
1039start_download_ctx_menu (GtkMenuItem *item, gpointer user_data)
1040{
1041 GtkTreePath *path;
1042 GtkTreeView *tv;
1043 struct StartDownloadContext sdc;
1044
1045 if (current_context_row_reference == NULL)
1046 {
1047 GNUNET_break (0);
1048 return;
1049 }
1050 path = gtk_tree_row_reference_get_path (current_context_row_reference);
1051 gtk_tree_row_reference_free (current_context_row_reference);
1052 current_context_row_reference = NULL;
1053 tv = GTK_TREE_VIEW (gtk_builder_get_object
1054 (current_context_search_tab->builder,
1055 "_search_result_frame"));
1056 sdc.tab = current_context_search_tab;
1057 sdc.recursive = FALSE;
1058 start_download (tv, path, NULL, &sdc);
1059 gtk_tree_path_free (path);
1060 current_context_search_tab = NULL;
1061}
1062
1063/**
1064 * "Download recursively" was selected in the current search context menu.
1065 */
1066static void
1067start_download_recursively_ctx_menu (GtkMenuItem *item, gpointer user_data)
1068{
1069 GtkTreePath *path;
1070 GtkTreeView *tv;
1071 struct StartDownloadContext sdc;
1072
1073 if (current_context_row_reference == NULL)
1074 {
1075 GNUNET_break (0);
1076 return;
1077 }
1078 path = gtk_tree_row_reference_get_path (current_context_row_reference);
1079 gtk_tree_row_reference_free (current_context_row_reference);
1080 current_context_row_reference = NULL;
1081 tv = GTK_TREE_VIEW (gtk_builder_get_object
1082 (current_context_search_tab->builder,
1083 "_search_result_frame"));
1084 sdc.tab = current_context_search_tab;
1085 sdc.recursive = TRUE;
1086 start_download (tv, path, NULL, &sdc);
1087 gtk_tree_path_free (path);
1088 current_context_search_tab = NULL;
1089}
1090 1231
1091 1232
1092/**
1093 * Download was selected in the current search context menu.
1094 */
1095static void
1096abort_download_ctx_menu (GtkMenuItem *item, gpointer user_data)
1097{
1098 struct DownloadEntry *de = user_data;
1099 1233
1100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1101 "Aborting a download DE=%p\n", de);
1102
1103 GNUNET_assert (de->dc != NULL);
1104 GNUNET_FS_download_stop (de->dc, GNUNET_YES);
1105 current_context_search_tab = NULL;
1106}
1107
1108
1109/**
1110 * Copy current URI to clipboard.
1111 */
1112static void
1113copy_uri_to_clipboard_ctx_menu (GtkMenuItem *item, gpointer user_data)
1114{
1115 GtkTreePath *path;
1116 GtkTreeView *tv;
1117 GtkTreeModel *tm;
1118 GtkTreeIter iter;
1119 struct GNUNET_FS_Uri *uri;
1120 char *uris;
1121 GtkClipboard *cb;
1122
1123 if (current_context_row_reference == NULL)
1124 {
1125 GNUNET_break (0);
1126 return;
1127 }
1128 path = gtk_tree_row_reference_get_path (current_context_row_reference);
1129 gtk_tree_row_reference_free (current_context_row_reference);
1130 current_context_row_reference = NULL;
1131 tv = GTK_TREE_VIEW (gtk_builder_get_object
1132 (current_context_search_tab->builder,
1133 "_search_result_frame"));
1134 tm = gtk_tree_view_get_model (tv);
1135 if (TRUE != gtk_tree_model_get_iter (tm, &iter, path))
1136 {
1137 GNUNET_break (0);
1138 gtk_tree_path_free (path);
1139 return;
1140 }
1141 gtk_tree_model_get (tm, &iter, 1, &uri, -1);
1142 gtk_tree_path_free (path);
1143 current_context_search_tab = NULL;
1144 if (uri == NULL)
1145 {
1146 GNUNET_break (0);
1147 return;
1148 }
1149 uris = GNUNET_FS_uri_to_string (uri);
1150 cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1151 gtk_clipboard_set_text (cb, uris, -1);
1152 gtk_clipboard_store (cb);
1153 GNUNET_free (uris);
1154}
1155 1234
1156gboolean 1235gboolean
1157search_list_on_popup (GtkWidget *widget, gpointer user_data) 1236search_list_on_popup (GtkWidget *widget, gpointer user_data)
@@ -1375,6 +1454,46 @@ stop_search (GtkButton * button, gpointer user_data)
1375} 1454}
1376 1455
1377 1456
1457static void
1458free_search_result (struct SearchResult *sr)
1459{
1460 GtkTreePath *tp;
1461 GtkTreeModel *tm;
1462 GtkTreeIter iter;
1463 struct GNUNET_FS_Uri *uri;
1464 struct GNUNET_CONTAINER_MetaData *meta;
1465
1466 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1467 "Freeing a search result SR=%p\n", sr);
1468
1469 if (sr == NULL)
1470 {
1471 GNUNET_break (0);
1472 return;
1473 }
1474 GNUNET_assert (sr->rr != NULL);
1475 tp = gtk_tree_row_reference_get_path (sr->rr);
1476 GNUNET_assert (tp != NULL);
1477 tm = gtk_tree_row_reference_get_model (sr->rr);
1478 GNUNET_assert (tm != NULL);
1479 if (TRUE != gtk_tree_model_get_iter (tm, &iter, tp))
1480 {
1481 GNUNET_break (0);
1482 gtk_tree_path_free (tp);
1483 return;
1484 }
1485 gtk_tree_path_free (tp);
1486 gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, -1);
1487 if (uri != NULL)
1488 GNUNET_FS_uri_destroy (uri);
1489 if (meta != NULL)
1490 GNUNET_CONTAINER_meta_data_destroy (meta);
1491 gtk_tree_row_reference_free (sr->rr);
1492 (void) gtk_tree_store_remove (GTK_TREE_STORE (tm), &iter);
1493 GNUNET_free (sr);
1494}
1495
1496
1378/** 1497/**
1379 * Stop completed downloads (or those that failed). Should 1498 * Stop completed downloads (or those that failed). Should
1380 * iterate over the underlying tree store and stop all 1499 * iterate over the underlying tree store and stop all
@@ -1924,44 +2043,6 @@ update_search_result (struct SearchResult *sr,
1924} 2043}
1925 2044
1926 2045
1927static void
1928free_search_result (struct SearchResult *sr)
1929{
1930 GtkTreePath *tp;
1931 GtkTreeModel *tm;
1932 GtkTreeIter iter;
1933 struct GNUNET_FS_Uri *uri;
1934 struct GNUNET_CONTAINER_MetaData *meta;
1935
1936 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1937 "Freeing a search result SR=%p\n", sr);
1938
1939 if (sr == NULL)
1940 {
1941 GNUNET_break (0);
1942 return;
1943 }
1944 GNUNET_assert (sr->rr != NULL);
1945 tp = gtk_tree_row_reference_get_path (sr->rr);
1946 GNUNET_assert (tp != NULL);
1947 tm = gtk_tree_row_reference_get_model (sr->rr);
1948 GNUNET_assert (tm != NULL);
1949 if (TRUE != gtk_tree_model_get_iter (tm, &iter, tp))
1950 {
1951 GNUNET_break (0);
1952 gtk_tree_path_free (tp);
1953 return;
1954 }
1955 gtk_tree_path_free (tp);
1956 gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, -1);
1957 if (uri != NULL)
1958 GNUNET_FS_uri_destroy (uri);
1959 if (meta != NULL)
1960 GNUNET_CONTAINER_meta_data_destroy (meta);
1961 gtk_tree_row_reference_free (sr->rr);
1962 (void) gtk_tree_store_remove (GTK_TREE_STORE (tm), &iter);
1963 GNUNET_free (sr);
1964}
1965 2046
1966 2047
1967/** 2048/**
@@ -2364,188 +2445,6 @@ GNUNET_GTK_main_window_notebook_switch_page_cb (GtkWidget * dummy,
2364 gtk_list_store_clear (ms); 2445 gtk_list_store_clear (ms);
2365} 2446}
2366 2447
2367static void
2368copy_metadata_to_clipboard (GtkTreeModel * model, GtkTreePath * path,
2369 GtkTreeIter * iter, gpointer user_data)
2370{
2371 gchar *type, *value;
2372 GList **l = (GList **) user_data;
2373
2374 gtk_tree_model_get (model, iter, 2, &type, 3, &value, -1);
2375
2376 *l = g_list_prepend (*l, type);
2377 *l = g_list_prepend (*l, value);
2378}
2379
2380void
2381metadata_copy_selection_activated (GtkMenuItem * menuitem, gpointer user_data)
2382{
2383 GtkBuilder *builder;
2384 GtkTreeView *tree;
2385 GtkClipboard *cb;
2386 GList *pairs = NULL, *l, *next, *value, *type;
2387 guint total_len;
2388 gchar *s, *p;
2389
2390 builder = GTK_BUILDER (user_data);
2391 tree =
2392 GTK_TREE_VIEW (gtk_builder_get_object
2393 (builder, "GNUNET_GTK_main_window_metadata_treeview"));
2394
2395 gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (tree),
2396 copy_metadata_to_clipboard, &pairs);
2397
2398 total_len = 0;
2399 pairs = g_list_reverse (pairs);
2400 for (l = pairs; l; l = next)
2401 {
2402 type = l;
2403 value = l->next;
2404 if (!value)
2405 break;
2406 next = value->next;
2407 total_len +=
2408 strlen ((gchar *) type->data) + strlen ((gchar *) value->data) +
2409 2 /* ": " */ + (next ? 1 : 0) /* "\n" */ ;
2410 }
2411 if (total_len > 0)
2412 {
2413 total_len += 1; /* "\0" */
2414 s = g_new0 (gchar, total_len);
2415 p = s;
2416 for (l = pairs; l; l = next)
2417 {
2418 type = l;
2419 value = l->next;
2420 if (value)
2421 {
2422 next = value->next;
2423 p = g_stpcpy (p, (gchar *) type->data);
2424 p = g_stpcpy (p, ": ");
2425 p = g_stpcpy (p, (gchar *) value->data);
2426 if (next)
2427 p = g_stpcpy (p, "\n");
2428 }
2429 else
2430 next = NULL;
2431 }
2432 }
2433 g_list_foreach (pairs, (GFunc) g_free, NULL);
2434 g_list_free (pairs);
2435 pairs = NULL;
2436
2437 if (total_len > 0)
2438 {
2439 cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
2440 gtk_clipboard_set_text (cb, s, -1);
2441 gtk_clipboard_store (cb);
2442 g_free (s);
2443 }
2444}
2445
2446void
2447metadata_menu_popup_position (GtkMenu * menu, gint * x, gint * y,
2448 gboolean * push_in, gpointer user_data)
2449{
2450 GtkBuilder *builder;
2451 GtkTreeView *tree;
2452 GtkTreeSelection *sel;
2453 GList *rows;
2454 GtkTreePath *p;
2455 GtkAllocation tree_allocation;
2456 GdkWindow *main_window_gdk;
2457 gint mwg_x, mwg_y, t_x, t_y, popup_x, popup_y;
2458
2459 builder = GTK_BUILDER (user_data);
2460
2461 tree =
2462 GTK_TREE_VIEW (gtk_builder_get_object
2463 (builder, "GNUNET_GTK_main_window_metadata_treeview"));
2464
2465 gtk_widget_get_allocation (GTK_WIDGET (tree), &tree_allocation);
2466
2467 main_window_gdk = gtk_widget_get_window (GTK_WIDGET (tree));
2468
2469 gdk_window_get_origin (main_window_gdk, &mwg_x, &mwg_y);
2470
2471 t_x = mwg_x + tree_allocation.x;
2472 t_y = mwg_y + tree_allocation.y;
2473 popup_x = t_x;
2474 popup_y = t_y;
2475
2476 sel = gtk_tree_view_get_selection (tree);
2477
2478 rows = gtk_tree_selection_get_selected_rows (sel, NULL);
2479
2480 if (rows->data)
2481 {
2482 GdkRectangle r;
2483
2484 p = (GtkTreePath *) rows->data;
2485 gtk_tree_view_get_cell_area (tree, p, NULL, &r);
2486 popup_x += r.x;
2487 popup_y += r.y;
2488 }
2489
2490 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
2491 g_list_free (rows);
2492 *x = popup_x;
2493 *y = popup_y;
2494 *push_in = FALSE;
2495}
2496
2497static void
2498do_metadata_popup_menu (GtkWidget * widget, GdkEventButton * event,
2499 gpointer user_data)
2500{
2501 GtkMenu *menu;
2502 GtkBuilder *builder;
2503 int button, event_time;
2504 GtkMenuPositionFunc mpf = NULL;
2505
2506 builder = GTK_BUILDER (user_data);
2507
2508 menu = GTK_MENU (gtk_builder_get_object (builder, "metadata_popup_menu"));
2509
2510 if (event)
2511 {
2512 button = event->button;
2513 event_time = event->time;
2514 }
2515 else
2516 {
2517 button = 0;
2518 event_time = gtk_get_current_event_time ();
2519 }
2520
2521 gtk_menu_popup (menu, NULL, NULL, mpf, user_data, button, event_time);
2522}
2523
2524gboolean
2525GNUNET_GTK_main_window_metadata_treeview_button_press_event_cb (GtkWidget *
2526 widget,
2527 GdkEventButton *
2528 event,
2529 gpointer
2530 user_data)
2531{
2532 /* Ignore double-clicks and triple-clicks */
2533 if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
2534 {
2535 do_metadata_popup_menu (widget, event, user_data);
2536 return TRUE;
2537 }
2538
2539 return FALSE;
2540}
2541
2542gboolean
2543GNUNET_GTK_main_window_metadata_treeview_popup_menu_cb (GtkWidget * widget,
2544 gpointer user_data)
2545{
2546 do_metadata_popup_menu (widget, NULL, user_data);
2547 return TRUE;
2548}
2549 2448
2550 2449
2551/* end of gnunet-fs-gtk-event_handler.c */ 2450/* end of gnunet-fs-gtk-event_handler.c */
diff --git a/src/fs/gnunet-fs-gtk-main_window_meta_data_context_menu.c b/src/fs/gnunet-fs-gtk-main_window_meta_data_context_menu.c
new file mode 100644
index 00000000..4f8edd53
--- /dev/null
+++ b/src/fs/gnunet-fs-gtk-main_window_meta_data_context_menu.c
@@ -0,0 +1,192 @@
1/*
2 This file is part of GNUnet.
3 (C) 2010, 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/fs/gnunet-fs-gtk-main_window_meta_data_context_menu.c
23 * @brief context menu for the 'meta data' tree view in the main window
24 * @author Christian Grothoff
25 */
26#include "gnunet-fs-gtk.h"
27#include "gnunet-fs-gtk-download.h"
28#include "gnunet-fs-gtk-event_handler.h"
29#include <string.h>
30
31
32
33/**
34 * Helper function of GNUNET_GTK_FS_metadata_copy_selection_activated
35 * which copies the (selected) entries from the tree view to the
36 * GList.
37 *
38 * @param model the tree model with the data
39 * @param path unused
40 * @param iter position in the model to access
41 * @param user_data 'GList**' where we should store the types and values found
42 */
43static void
44copy_metadata_to_clipboard (GtkTreeModel * model, GtkTreePath * path,
45 GtkTreeIter * iter, gpointer user_data)
46{
47 GList **l = user_data;
48 gchar *type;
49 gchar *value;
50
51 gtk_tree_model_get (model, iter, 2, &type, 3, &value, -1);
52 *l = g_list_prepend (*l, type);
53 *l = g_list_prepend (*l, value);
54}
55
56
57/**
58 * User activated metadata pop up menu "Copy selection" entry.
59 *
60 * @param menuitem the 'copy selection' menu item
61 * @param user_data the GtkBuilder of the main window
62 */
63void
64GNUNET_GTK_FS_metadata_copy_selection_activated (GtkMenuItem * menuitem,
65 gpointer user_data)
66{
67 GtkBuilder *builder = GTK_BUILDER (user_data);
68 GtkTreeView *tree;
69 GtkClipboard *cb;
70 GList *pairs;
71 GList *pos;
72 GList *value;
73 GList *type;
74 guint total_len;
75 gchar *s;
76 gchar *p;
77
78 tree =
79 GTK_TREE_VIEW (gtk_builder_get_object
80 (builder, "GNUNET_GTK_main_window_metadata_treeview"));
81 pairs = NULL;
82 gtk_tree_selection_selected_foreach (gtk_tree_view_get_selection (tree),
83 &copy_metadata_to_clipboard, &pairs);
84 if (NULL == pairs)
85 return; /* nothing selected */
86 total_len = 0;
87 pairs = g_list_reverse (pairs);
88 for (pos = pairs; NULL != pos; pos = value->next)
89 {
90 type = pos;
91 value = pos->next;
92 GNUNET_assert (NULL != value);
93 total_len +=
94 strlen ((gchar *) type->data) + strlen ((gchar *) value->data) +
95 2 /* ": " */ + ((NULL != value->next) ? 1 : 0) /* "\n" */ ;
96 }
97 GNUNET_assert (total_len > 0);
98 total_len++; /* "\0" */
99 s = g_new0 (gchar, total_len);
100 if (NULL == s)
101 {
102 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "malloc");
103 return;
104 }
105 p = s;
106 for (pos = pairs; NULL != pos; pos = value->next)
107 {
108 type = pos;
109 value = pos->next;
110 GNUNET_assert (NULL != value);
111 p = g_stpcpy (p, (gchar *) type->data);
112 p = g_stpcpy (p, ": ");
113 p = g_stpcpy (p, (gchar *) value->data);
114 if (NULL != value->next)
115 p = g_stpcpy (p, "\n");
116 }
117 g_list_foreach (pairs, (GFunc) &g_free, NULL);
118 g_list_free (pairs);
119 cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
120 gtk_clipboard_set_text (cb, s, -1);
121 gtk_clipboard_store (cb);
122 g_free (s);
123}
124
125
126/**
127 * Got asked to pop up the context menu in the metadata treeview in
128 * the main window. Do it.
129 *
130 * @param button which button caused the event (0 for none)
131 * @param event_time time of the event (current time or 'event->time')
132 * @param user_data the gtk builder of the main window
133 */
134static void
135do_metadata_popup_menu (int button,
136 int event_time,
137 GtkBuilder *builder)
138{
139 GtkMenu *menu;
140
141 menu = GTK_MENU (gtk_builder_get_object (builder, "metadata_popup_menu"));
142 gtk_menu_popup (menu, NULL, NULL, NULL, builder, button, event_time);
143}
144
145
146/**
147 * Got a button press event on the metadata treeview in the main window.
148 * If it was a right click, pop up the context menu.
149 *
150 * @param widget the tree view widget
151 * @param user_data the gtk builder of the main window
152 */
153gboolean
154GNUNET_GTK_main_window_metadata_treeview_button_press_event_cb (GtkWidget *
155 widget,
156 GdkEventButton *
157 event,
158 gpointer
159 user_data)
160{
161 GtkBuilder *builder = GTK_BUILDER (user_data);
162
163 /* Ignore double-clicks and triple-clicks */
164 if ( (event->button != 3) || (event->type != GDK_BUTTON_PRESS) )
165 return FALSE;
166 do_metadata_popup_menu (event->button,
167 event->time,
168 builder);
169 return TRUE;
170}
171
172
173/**
174 * Metadata treeview in the main window got the 'popup-menu' signal.
175 * Pop up the menu.
176 *
177 * @param widget the tree view widget
178 * @param user_data the gtk builder of the main window
179 */
180gboolean
181GNUNET_GTK_main_window_metadata_treeview_popup_menu_cb (GtkWidget * widget,
182 gpointer user_data)
183{
184 GtkBuilder *builder = GTK_BUILDER (user_data);
185
186 do_metadata_popup_menu (0 /* no button */,
187 gtk_get_current_event_time (),
188 builder);
189 return TRUE;
190}
191
192/* end of gnunet-fs-gtk-meta_data_context_menu.c */