aboutsummaryrefslogtreecommitdiff
path: root/src/fs/gnunet-fs-gtk_event-handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs/gnunet-fs-gtk_event-handler.c')
-rw-r--r--src/fs/gnunet-fs-gtk_event-handler.c627
1 files changed, 258 insertions, 369 deletions
diff --git a/src/fs/gnunet-fs-gtk_event-handler.c b/src/fs/gnunet-fs-gtk_event-handler.c
index 737dfca5..42780d4b 100644
--- a/src/fs/gnunet-fs-gtk_event-handler.c
+++ b/src/fs/gnunet-fs-gtk_event-handler.c
@@ -262,11 +262,16 @@ static struct SearchTab *uri_tab;
262static struct PublishTab *publish_tab; 262static struct PublishTab *publish_tab;
263 263
264/** 264/**
265 * Special tab we use to store publishing operations. 265 * Currently displayed search tab
266 */ 266 */
267static struct SearchTab *current_search_tab = NULL; 267static struct SearchTab *current_search_tab = NULL;
268 268
269/** 269/**
270 * Currently selected row in a search tab.
271 */
272static GtkTreePath *current_selected_search_result = NULL;
273
274/**
270 * Animation to display while publishing. 275 * Animation to display while publishing.
271 */ 276 */
272static struct GNUNET_FS_AnimationContext *animation_publishing; 277static struct GNUNET_FS_AnimationContext *animation_publishing;
@@ -393,120 +398,6 @@ get_default_download_directory (char *buffer, size_t size)
393} 398}
394 399
395/** 400/**
396 * Called recursively to build a suggested filename by prepending
397 * suggested names for its parent directories (if any).
398 *
399 * @param tm tree model this function gets the data from
400 * @param iter current position in the tree, for which we want a suggested filename
401 * @param top GNUNET_YES for the original call to this function,
402 * GNUNET_NO for recursive calls; used to decide if the
403 * current call is eligible to set 'anonymity' and 'local_parents'
404 * @param local_parents set to GNUNET_YES if all parents are directories, and are downloaded.
405 * @param anonymity set to the anonymity level of the closest ancestor download (if any);
406 * set to "-1" for uninitialized initially (will be left at -1 if
407 * no suitable parent download was found)
408 * @param filename_is_absolute set to GNUNET_YES if the suggestion is an absolute filename,
409 * GNUNET_NO for relative filenames (gotten from meta data)
410 * @return suggested filename, possibly NULL
411 */
412static char *
413get_suggested_filename_anonymity (GtkTreeModel *tm,
414 GtkTreeIter *iter,
415 int top,
416 int *local_parents,
417 int *anonymity,
418 int *filename_is_absolute)
419{
420 char *result;
421 char *dirname;
422 char *local_filename;
423 char *filename;
424 int downloaded_anonymity;
425 int have_a_parent;
426 struct GNUNET_CONTAINER_MetaData *meta;
427 GtkTreeIter parent;
428 const char *basename;
429 char *dot;
430
431 /* FIXME-BUG-MAYBE: this function is likely responsible for not always
432 suggesting the best filename... To be investigated some more... */
433 gtk_tree_model_get (tm, iter,
434 SEARCH_TAB_MC_METADATA, &meta,
435 SEARCH_TAB_MC_DOWNLOADED_FILENAME, &local_filename,
436 SEARCH_TAB_MC_DOWNLOADED_ANONYMITY,
437 &downloaded_anonymity,
438 -1);
439 if (GNUNET_NO == top)
440 {
441 if (NULL != local_filename)
442 *local_parents = GNUNET_YES;
443 else
444 *local_parents = GNUNET_NO;
445 if ( (downloaded_anonymity != -1) &&
446 (*anonymity == -1) )
447 *anonymity = downloaded_anonymity;
448 }
449 if (gtk_tree_model_iter_parent (tm, &parent, iter))
450 {
451 have_a_parent = GNUNET_YES;
452 dirname = get_suggested_filename_anonymity (tm, &parent, GNUNET_NO,
453 local_parents, anonymity,
454 filename_is_absolute);
455 }
456 else
457 {
458 have_a_parent = GNUNET_NO;
459 dirname = NULL;
460 }
461 if (local_filename == NULL)
462 {
463 filename = GNUNET_FS_meta_data_suggest_filename (meta);
464 }
465 else
466 {
467 /* This directory was downloaded as /foo/bar/baz/somedirname
468 * Hopefully, "somedirname" is actually "somedir.gnd"
469 * We need to strip the ".gnd" part to get "somedir", which is
470 * what we're going to use instead of suggested original filename
471 * Without the .gnd extension we're going to just use a copy
472 * of the directory file name - and that would fail. Sad.
473 */
474 if ( (NULL == dirname) && (GNUNET_NO == have_a_parent))
475 {
476 /* This is the root. Use absolute path. */
477 basename = (const char *) local_filename;
478 *filename_is_absolute = GNUNET_YES;
479 }
480 else
481 {
482 basename = GNUNET_STRINGS_get_short_name (local_filename);
483 }
484 if ( (NULL != basename) && (strlen (basename) > 0) )
485 {
486 filename = GNUNET_strdup (basename);
487 dot = strrchr (filename, '.');
488 if (dot)
489 *dot = '\0';
490 }
491 else
492 {
493 filename = GNUNET_FS_meta_data_suggest_filename (meta);
494 }
495 }
496 if ( (NULL != dirname) && (NULL != filename) )
497 {
498 GNUNET_asprintf (&result, "%s%s%s", dirname, DIR_SEPARATOR_STR, filename);
499 GNUNET_free (filename);
500 GNUNET_free (dirname);
501 return result;
502 }
503 if (NULL != filename)
504 return filename;
505 return NULL;
506}
507
508
509/**
510 * finished_chain - non-NULL for top-level call (for the item we're about to download), NULL otherwise 401 * finished_chain - non-NULL for top-level call (for the item we're about to download), NULL otherwise
511 * function sets it to GNUNET_YES if the item we're about to download was, in fact, already downloaded once, and thus we provide a name for it, 402 * function sets it to GNUNET_YES if the item we're about to download was, in fact, already downloaded once, and thus we provide a name for it,
512 * returning a finished relative filename that might only need .gnd appended to it, nothing else. 403 * returning a finished relative filename that might only need .gnd appended to it, nothing else.
@@ -586,6 +477,9 @@ build_relative_name (GtkTreeModel *tm,
586 gchar *bname = g_path_get_basename (filename); 477 gchar *bname = g_path_get_basename (filename);
587 int chain_ok; 478 int chain_ok;
588 char *dot_gnd; 479 char *dot_gnd;
480 /* FIXME: Use better checking (don't compare paths as strings,
481 * only verify directory inode is the same, or something).
482 */
589#if WINDOWS 483#if WINDOWS
590 /* Kind of stricmp() for utf-8 */ 484 /* Kind of stricmp() for utf-8 */
591 gchar *tmp = g_utf8_casefold (our_dirname, -1); 485 gchar *tmp = g_utf8_casefold (our_dirname, -1);
@@ -631,6 +525,18 @@ build_relative_name (GtkTreeModel *tm,
631} 525}
632 526
633 527
528/**
529 * Builds a suggested filename by prepending
530 * suggested names for its parent directories (if any).
531 *
532 * @param tm tree model this function gets the data from
533 * @param iter current position in the tree, for which we want a suggested filename
534 * @param download_directory will receive a pointer to download directory.
535 * free it with GNUNET_free() when done.
536 * Will never be NULL on return (CWD will be used as a fallback).
537 * @param anonymity will receive suggested anonymity (or -1 if anonymity can't be suggested)
538 * @return suggested filename relative to download directory (free with GNUNET_free()), or NULL
539 */
634static char * 540static char *
635get_suggested_filename_anonymity2 (GtkTreeModel *tm, 541get_suggested_filename_anonymity2 (GtkTreeModel *tm,
636 GtkTreeIter *iter, 542 GtkTreeIter *iter,
@@ -642,7 +548,7 @@ get_suggested_filename_anonymity2 (GtkTreeModel *tm,
642 char *relname; 548 char *relname;
643 char *filename; 549 char *filename;
644 char *tmp; 550 char *tmp;
645 int downloaded_anonymity; 551 int downloaded_anonymity = -1;
646 struct GNUNET_CONTAINER_MetaData *meta; 552 struct GNUNET_CONTAINER_MetaData *meta;
647 size_t tmplen; 553 size_t tmplen;
648 int finished_chain; 554 int finished_chain;
@@ -697,7 +603,10 @@ get_suggested_filename_anonymity2 (GtkTreeModel *tm,
697 result = GNUNET_strdup (tmp); 603 result = GNUNET_strdup (tmp);
698 } 604 }
699 } 605 }
606 else
607 result = NULL;
700 *download_directory = GNUNET_strdup (downloaddir); 608 *download_directory = GNUNET_strdup (downloaddir);
609 *anonymity = downloaded_anonymity;
701 GNUNET_free (filename); 610 GNUNET_free (filename);
702 g_free (downloaddir); 611 g_free (downloaddir);
703 g_free (relname); 612 g_free (relname);
@@ -705,141 +614,6 @@ get_suggested_filename_anonymity2 (GtkTreeModel *tm,
705} 614}
706 615
707/** 616/**
708 * This function is called when the user double-clicks on a search
709 * result. Begins the download, if necessary by opening the "save as"
710 * window.
711 *
712 * @param tree_view tree view with the details
713 * @param path path selecting which entry we want to download
714 * @param tab the search tab where the user triggered the download request
715 * @param is_recursive was the request for a recursive download?
716 * @param save_as force opening the 'save as' dialog?
717 */
718static void
719start_download (GtkTreeView *tree_view,
720 GtkTreePath *path,
721 struct SearchTab *tab,
722 int is_recursive,
723 int save_as)
724{
725 GtkTreeModel *tm;
726 GtkTreeIter iter;
727 struct GNUNET_FS_Uri *uri;
728 struct GNUNET_CONTAINER_MetaData *meta;
729 struct SearchResult *sr;
730 struct DownloadEntry *de;
731 char *buf = NULL;
732 char *tmp;
733 size_t tmplen;
734 char cwd[FILENAME_MAX];
735 char *download_directory;
736 char *filename;
737 int local_parents;
738 int have_a_suggestion;
739 int anonymity;
740 int filename_is_absolute;
741
742 tm = gtk_tree_view_get_model (tree_view);
743 if (TRUE != gtk_tree_model_get_iter (tm, &iter, path))
744 {
745 GNUNET_break (0);
746 return;
747 }
748 gtk_tree_model_get (tm, &iter,
749 SEARCH_TAB_MC_METADATA, &meta,
750 SEARCH_TAB_MC_URI, &uri,
751 SEARCH_TAB_MC_SEARCH_RESULT, &sr,
752 -1);
753 if (NULL == uri)
754 {
755 /* user clicked on directory that was opened (not downloaded!), so we
756 have no URI and downloading makes no sense. Ignore! */
757 return;
758 }
759 if (NULL != sr->download)
760 {
761 /* download already active! */
762 return;
763 }
764 if (!(GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri)))
765 {
766 /* can only download chk/loc URIs, ignore */
767 /* break because in this case, we should not have even gotten here */
768 GNUNET_break (0);
769 return;
770 }
771
772 download_directory = get_default_download_directory (cwd, sizeof (cwd));
773 /* If no download directory is known, try working directory */
774 if (download_directory == NULL)
775 download_directory = getcwd (cwd, sizeof (cwd));
776 /* Calculate suggested filename */
777 local_parents = GNUNET_NO;
778 anonymity = -1;
779 filename_is_absolute = GNUNET_NO;
780 filename = get_suggested_filename_anonymity (tm, &iter, GNUNET_YES,
781 &local_parents, &anonymity,
782 &filename_is_absolute);
783 have_a_suggestion = GNUNET_NO;
784 if (NULL != download_directory)
785 {
786 if (NULL == filename)
787 {
788 buf = GNUNET_strdup (download_directory);
789 }
790 else
791 {
792 have_a_suggestion = GNUNET_YES;
793 if (filename_is_absolute)
794 GNUNET_asprintf (&tmp, "%s", filename);
795 else
796 GNUNET_asprintf (&tmp, "%s%s%s",
797 download_directory,
798 DIR_SEPARATOR_STR,
799 filename);
800 tmplen = strlen (tmp);
801 /* now, if we have a directory, replace trailing '/' with ".gnd" */
802 if (GNUNET_YES ==
803 GNUNET_FS_meta_data_test_for_directory (meta))
804 {
805 if ( (tmp[tmplen-1] == '/') ||
806 (tmp[tmplen-1] == '\\') )
807 tmp[tmplen-1] = '\0';
808 GNUNET_asprintf (&buf,
809 "%s%s",
810 tmp,
811 GNUNET_FS_DIRECTORY_EXT);
812 GNUNET_free (tmp);
813 }
814 else
815 {
816 buf = tmp;
817 }
818 }
819 }
820 GNUNET_free_non_null (filename);
821
822 /* now setup everything for the save-as dialog */
823 de = GNUNET_malloc (sizeof (struct DownloadEntry));
824 de->uri = GNUNET_FS_uri_dup (uri);
825 de->filename = buf;
826 de->sr = sr;
827 sr->download = de;
828 de->anonymity = anonymity;
829 de->is_recursive = is_recursive;
830 de->is_directory = GNUNET_FS_meta_data_test_for_directory (meta);
831 if (save_as)
832 have_a_suggestion = GNUNET_NO;
833 if ( (GNUNET_YES == local_parents) &&
834 (GNUNET_YES == have_a_suggestion) )
835 /* Skip the dialog, call directly */
836 GNUNET_FS_GTK_download_context_start_download (de);
837 else
838 GNUNET_FS_GTK_open_download_as_dialog (de);
839}
840
841
842/**
843 * Context for the search list popup menu. 617 * Context for the search list popup menu.
844 */ 618 */
845struct SearchListPopupContext 619struct SearchListPopupContext
@@ -879,79 +653,6 @@ search_list_popup_selection_done (GtkMenuShell *menushell,
879 GNUNET_free (spc); 653 GNUNET_free (spc);
880} 654}
881 655
882
883/**
884 * This function is called when the user double-clicks on a search
885 * result. Begins the download, if necessary by opening the "save as"
886 * window.
887 *
888 * @param tree_view tree view with the details
889 * @param path path selecting which entry we want to download
890 * @param column unused entry specifying which column the mouse was in
891 * @param user_data the 'struct SearchTab' that was activated
892 */
893void
894GNUNET_FS_GTK_search_treeview_row_activated (GtkTreeView * tree_view,
895 GtkTreePath * path,
896 GtkTreeViewColumn * column,
897 gpointer user_data)
898{
899 struct SearchTab *tab = user_data;
900 struct GNUNET_FS_Uri *uri;
901 GtkTreeModel *tm;
902 GtkTreeIter iter;
903
904 tm = gtk_tree_view_get_model (tree_view);
905 if (TRUE != gtk_tree_model_get_iter (tm, &iter, path))
906 {
907 GNUNET_break (0);
908 return;
909 }
910 gtk_tree_model_get (tm, &iter,
911 SEARCH_TAB_MC_URI, &uri, -1);
912 if (NULL == uri)
913 {
914 /* user clicked on directory that was opened (not downloaded!), so we
915 have no URI and downloading makes no sense. Ignore! */
916 return;
917 }
918 if (GNUNET_FS_uri_test_ksk (uri) ||
919 GNUNET_FS_uri_test_sks (uri))
920 {
921 GNUNET_FS_GTK_handle_uri (uri, 1);
922 return;
923 }
924 /* must be chk/loc URI, start download */
925 start_download (tree_view, path, tab, GNUNET_NO, GNUNET_NO);
926}
927
928
929/**
930 * "Download" was selected in the current search context menu.
931 *
932 * @param spc the 'struct SearchListPopupContext' of the menu
933 * @param is_recursive was this the 'recursive' option?
934 * @parma save_as was this the 'save as' option?
935 */
936static void
937start_download_ctx_menu_helper (struct SearchListPopupContext *spc,
938 int is_recursive,
939 int save_as)
940{
941 GtkTreePath *path;
942 GtkTreeView *tv;
943
944 path = gtk_tree_row_reference_get_path (spc->rr);
945 tv = GTK_TREE_VIEW (gtk_builder_get_object
946 (spc->tab->builder,
947 "_search_result_frame"));
948 start_download (tv, path, spc->tab,
949 is_recursive,
950 save_as);
951 gtk_tree_path_free (path);
952}
953
954
955/** 656/**
956 * Selected row has changed in search result tree view, update preview 657 * Selected row has changed in search result tree view, update preview
957 * and metadata areas. 658 * and metadata areas.
@@ -964,8 +665,14 @@ GNUNET_FS_GTK_search_treeview_cursor_changed (GtkTreeView *tv,
964 gpointer user_data); 665 gpointer user_data);
965 666
966 667
668/**
669 * save_as - GNUNET_YES to open SaveAs dialog, GNUNET_NO to start downloading.
670 * download_directly - GNUNET_YES to make SaveAs dialog initiate the download,
671 * GNUNET_NO to only change names on the download panel.
672 * Ingored if save_as is GNUNET_NO.
673 */
967static void 674static void
968start_download2 () 675start_download2 (int save_as, int download_directly)
969{ 676{
970 struct GNUNET_GTK_MainWindowContext *mctx = GNUNET_FS_GTK_get_main_context (); 677 struct GNUNET_GTK_MainWindowContext *mctx = GNUNET_FS_GTK_get_main_context ();
971 struct SearchTab *st = GNUNET_FS_GTK_get_current_search_tab (); 678 struct SearchTab *st = GNUNET_FS_GTK_get_current_search_tab ();
@@ -998,6 +705,16 @@ start_download2 ()
998 SEARCH_TAB_MC_SEARCH_RESULT, &sr, 705 SEARCH_TAB_MC_SEARCH_RESULT, &sr,
999 -1); 706 -1);
1000 707
708 if (uri == NULL)
709 return;
710
711 if (GNUNET_FS_uri_test_ksk (uri) ||
712 GNUNET_FS_uri_test_sks (uri))
713 {
714 GNUNET_FS_GTK_handle_uri (uri, 1);
715 return;
716 }
717
1001 if (!((NULL == sr->download) && (NULL != uri) && 718 if (!((NULL == sr->download) && (NULL != uri) &&
1002 ((GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri))))) 719 ((GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri)))))
1003 return; 720 return;
@@ -1031,14 +748,56 @@ start_download2 ()
1031 de->is_recursive = recursive; 748 de->is_recursive = recursive;
1032 de->is_directory = GNUNET_FS_meta_data_test_for_directory (meta); 749 de->is_directory = GNUNET_FS_meta_data_test_for_directory (meta);
1033 750
1034 GNUNET_FS_GTK_download_context_start_download (de); 751 if (save_as == GNUNET_NO)
752 GNUNET_FS_GTK_download_context_start_download (de);
753 else if (download_directly == GNUNET_YES)
754 GNUNET_FS_GTK_open_download_as_dialog (de);
755 else
756 GNUNET_FS_GTK_open_change_download_name_dialog (de);
1035 757
1036 gtk_tree_path_free (path); 758 gtk_tree_path_free (path);
1037 g_free (downloaddir); 759 g_free (downloaddir);
1038 760
1039 if (GNUNET_GTK_tree_model_get_next_flat_iter (model, &iter, !recursive, &next_item)) 761 if (!save_as)
1040 gtk_tree_selection_select_iter (sel, &next_item); 762 {
1041 GNUNET_FS_GTK_search_treeview_cursor_changed (tv, st); 763 if (GNUNET_GTK_tree_model_get_next_flat_iter (model, &iter, !recursive, &next_item))
764 gtk_tree_selection_select_iter (sel, &next_item);
765 GNUNET_FS_GTK_search_treeview_cursor_changed (tv, st);
766 }
767}
768
769/**
770 * "Download" was selected in the current search context menu.
771 *
772 * @param spc the 'struct SearchListPopupContext' of the menu
773 * @param is_recursive was this the 'recursive' option?
774 * @parma save_as was this the 'save as' option?
775 */
776static void
777start_download_ctx_menu_helper (struct SearchListPopupContext *spc,
778 int is_recursive,
779 int save_as)
780{
781 start_download2 (save_as, GNUNET_YES);
782}
783
784/**
785 * This function is called when the user double-clicks on a search
786 * result. Begins the download, if necessary by opening the "save as"
787 * window.
788 *
789 * @param tree_view tree view with the details
790 * @param path path selecting which entry we want to download
791 * @param column unused entry specifying which column the mouse was in
792 * @param user_data the 'struct SearchTab' that was activated
793 */
794void
795GNUNET_FS_GTK_search_treeview_row_activated (GtkTreeView * tree_view,
796 GtkTreePath * path,
797 GtkTreeViewColumn * column,
798 gpointer user_data)
799{
800 start_download2 (GNUNET_NO, GNUNET_NO);
1042} 801}
1043 802
1044 803
@@ -1052,7 +811,21 @@ void
1052GNUNET_GTK_search_frame_download_download_button_clicked_cb ( 811GNUNET_GTK_search_frame_download_download_button_clicked_cb (
1053 GtkButton *button, gpointer user_data) 812 GtkButton *button, gpointer user_data)
1054{ 813{
1055 start_download2 (); 814 start_download2 (GNUNET_NO, GNUNET_NO);
815}
816
817/**
818 * User clicked on "..." button at the download options panel, next
819 * to the Download As entry.
820 *
821 * @param button the "..." button
822 * @param user_data the main window context
823 */
824void
825GNUNET_GTK_search_frame_download_filename_change_button_clicked_cb (
826 GtkButton *button, gpointer user_data)
827{
828 start_download2 (GNUNET_YES, GNUNET_NO);
1056} 829}
1057 830
1058 831
@@ -1093,10 +866,9 @@ start_download_recursively_ctx_menu (GtkMenuItem *item, gpointer user_data)
1093 * @param user_data the 'struct SearchListPopupContext' of the menu 866 * @param user_data the 'struct SearchListPopupContext' of the menu
1094 */ 867 */
1095static void 868static void
1096start_download_as_ctx_menu (GtkMenuItem *item, gpointer user_data) 869download_as_ctx_menu (GtkMenuItem *item, gpointer user_data)
1097{ 870{
1098 struct SearchListPopupContext *spc = user_data; 871 struct SearchListPopupContext *spc = user_data;
1099
1100 start_download_ctx_menu_helper (spc, GNUNET_NO, GNUNET_YES); 872 start_download_ctx_menu_helper (spc, GNUNET_NO, GNUNET_YES);
1101} 873}
1102 874
@@ -1112,9 +884,12 @@ abort_download_ctx_menu (GtkMenuItem *item, gpointer user_data)
1112{ 884{
1113 struct SearchListPopupContext *spc = user_data; 885 struct SearchListPopupContext *spc = user_data;
1114 struct DownloadEntry *de = spc->sr->download; 886 struct DownloadEntry *de = spc->sr->download;
887 GtkTreeView *tv;
1115 888
1116 GNUNET_assert (de->dc != NULL); 889 GNUNET_assert (de->dc != NULL);
1117 GNUNET_FS_download_stop (de->dc, GNUNET_YES); 890 GNUNET_FS_download_stop (de->dc, GNUNET_YES);
891 tv = GTK_TREE_VIEW (gtk_builder_get_object (spc->tab->builder, "_search_result_frame"));
892 GNUNET_FS_GTK_search_treeview_cursor_changed (tv, spc->tab);
1118} 893}
1119 894
1120 895
@@ -1187,6 +962,8 @@ search_list_popup (GtkTreeModel *tm,
1187 struct SearchResult *sr; 962 struct SearchResult *sr;
1188 struct GNUNET_FS_Uri *uri; 963 struct GNUNET_FS_Uri *uri;
1189 struct SearchListPopupContext *spc; 964 struct SearchListPopupContext *spc;
965 struct GNUNET_CONTAINER_MetaData *meta;
966 gboolean is_directory = FALSE;
1190 967
1191 spc = GNUNET_malloc (sizeof (struct SearchListPopupContext)); 968 spc = GNUNET_malloc (sizeof (struct SearchListPopupContext));
1192 spc->tab = tab; 969 spc->tab = tab;
@@ -1195,8 +972,12 @@ search_list_popup (GtkTreeModel *tm,
1195 gtk_tree_path_free (path); 972 gtk_tree_path_free (path);
1196 gtk_tree_model_get (tm, iter, 973 gtk_tree_model_get (tm, iter,
1197 SEARCH_TAB_MC_URI, &uri, 974 SEARCH_TAB_MC_URI, &uri,
975 SEARCH_TAB_MC_METADATA, &meta,
1198 SEARCH_TAB_MC_SEARCH_RESULT, &sr, 976 SEARCH_TAB_MC_SEARCH_RESULT, &sr,
1199 -1); 977 -1);
978 if (meta != NULL)
979 is_directory = GNUNET_FS_meta_data_test_for_directory (meta);
980
1200 spc->sr = sr; 981 spc->sr = sr;
1201 menu = GTK_MENU (gtk_menu_new ()); 982 menu = GTK_MENU (gtk_menu_new ());
1202 if ( (NULL == sr->download) && 983 if ( (NULL == sr->download) &&
@@ -1212,19 +993,22 @@ search_list_popup (GtkTreeModel *tm,
1212 TRUE); 993 TRUE);
1213 gtk_widget_show (child); 994 gtk_widget_show (child);
1214 gtk_menu_shell_append (GTK_MENU_SHELL (menu), child); 995 gtk_menu_shell_append (GTK_MENU_SHELL (menu), child);
1215 996
1216 child = gtk_menu_item_new_with_label (_("Download _recursively")); 997 if (is_directory)
1217 g_signal_connect (child, "activate", 998 {
1218 G_CALLBACK (start_download_recursively_ctx_menu), spc); 999 child = gtk_menu_item_new_with_label (_("Download _recursively"));
1219 gtk_label_set_use_underline (GTK_LABEL 1000 g_signal_connect (child, "activate",
1220 (gtk_bin_get_child (GTK_BIN (child))), 1001 G_CALLBACK (start_download_recursively_ctx_menu), spc);
1221 TRUE); 1002 gtk_label_set_use_underline (GTK_LABEL
1222 gtk_widget_show (child); 1003 (gtk_bin_get_child (GTK_BIN (child))),
1223 gtk_menu_shell_append (GTK_MENU_SHELL (menu), child); 1004 TRUE);
1005 gtk_widget_show (child);
1006 gtk_menu_shell_append (GTK_MENU_SHELL (menu), child);
1007 }
1224 1008
1225 child = gtk_menu_item_new_with_label (_("Download _as...")); 1009 child = gtk_menu_item_new_with_label (_("Download _as..."));
1226 g_signal_connect (child, "activate", 1010 g_signal_connect (child, "activate",
1227 G_CALLBACK (start_download_as_ctx_menu), spc); 1011 G_CALLBACK (download_as_ctx_menu), spc);
1228 gtk_label_set_use_underline (GTK_LABEL 1012 gtk_label_set_use_underline (GTK_LABEL
1229 (gtk_bin_get_child (GTK_BIN (child))), 1013 (gtk_bin_get_child (GTK_BIN (child))),
1230 TRUE); 1014 TRUE);
@@ -1773,6 +1557,7 @@ GNUNET_FS_GTK_search_treeview_cursor_changed (GtkTreeView *tv,
1773 GtkTreeIter iter; 1557 GtkTreeIter iter;
1774 struct GNUNET_CONTAINER_MetaData *meta; 1558 struct GNUNET_CONTAINER_MetaData *meta;
1775 GdkPixbuf *pixbuf; 1559 GdkPixbuf *pixbuf;
1560 GtkTreePath *selpath;
1776 struct SearchResult *sr; 1561 struct SearchResult *sr;
1777 struct GNUNET_FS_Uri *uri; 1562 struct GNUNET_FS_Uri *uri;
1778 struct GNUNET_GTK_MainWindowContext *mctx = GNUNET_FS_GTK_get_main_context (); 1563 struct GNUNET_GTK_MainWindowContext *mctx = GNUNET_FS_GTK_get_main_context ();
@@ -1785,6 +1570,9 @@ GNUNET_FS_GTK_search_treeview_cursor_changed (GtkTreeView *tv,
1785 /* nothing selected, clear preview */ 1570 /* nothing selected, clear preview */
1786 gtk_image_clear (mctx->preview_image); 1571 gtk_image_clear (mctx->preview_image);
1787 gtk_widget_hide (GTK_WIDGET (mctx->download_panel)); 1572 gtk_widget_hide (GTK_WIDGET (mctx->download_panel));
1573 if (current_selected_search_result != NULL)
1574 gtk_tree_path_free (current_selected_search_result);
1575 current_selected_search_result = NULL;
1788 return; 1576 return;
1789 } 1577 }
1790 meta = NULL; 1578 meta = NULL;
@@ -1797,38 +1585,48 @@ GNUNET_FS_GTK_search_treeview_cursor_changed (GtkTreeView *tv,
1797 SEARCH_TAB_MC_SEARCH_RESULT, &sr, 1585 SEARCH_TAB_MC_SEARCH_RESULT, &sr,
1798 -1); 1586 -1);
1799 1587
1800 if ((NULL == sr->download) && (NULL != uri) && 1588 selpath = gtk_tree_model_get_path (model, &iter);
1801 ((GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri)))) 1589 if (current_selected_search_result == NULL || gtk_tree_path_compare (selpath, current_selected_search_result) != 0)
1802 { 1590 {
1803 char *download_directory; 1591 if ((NULL == sr->download) && (NULL != uri) &&
1804 char *filename; 1592 ((GNUNET_FS_uri_test_chk (uri) || GNUNET_FS_uri_test_loc (uri))))
1805 int anonymity; 1593 {
1806 int is_directory; 1594 char *download_directory;
1595 char *filename;
1596 int anonymity;
1597 int is_directory;
1807 1598
1808 /* Calculate suggested filename */ 1599 /* Calculate suggested filename */
1809 anonymity = -1; 1600 anonymity = -1;
1810 download_directory = NULL; 1601 download_directory = NULL;
1811 filename = get_suggested_filename_anonymity2 (model, &iter, 1602 filename = get_suggested_filename_anonymity2 (model, &iter,
1812 &download_directory, &anonymity); 1603 &download_directory, &anonymity);
1813 1604
1814 is_directory = GNUNET_FS_meta_data_test_for_directory (meta); 1605 is_directory = GNUNET_FS_meta_data_test_for_directory (meta);
1815 gtk_widget_set_sensitive (GTK_WIDGET (mctx->download_recursive_checkbutton), is_directory); 1606 gtk_widget_set_sensitive (GTK_WIDGET (mctx->download_recursive_checkbutton), is_directory);
1816 1607
1817 /* TODO: make this configurable */ 1608 /* TODO: make this configurable */
1818 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mctx->download_recursive_checkbutton), is_directory); 1609 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mctx->download_recursive_checkbutton), is_directory);
1819 1610
1820 /* TODO: make this configurable */ 1611 /* TODO: make this configurable */
1821 GNUNET_GTK_select_anonymity_combo_level (mctx->download_anonymity_combo, anonymity >= 0 ? anonymity : 1); 1612 GNUNET_GTK_select_anonymity_combo_level (mctx->download_anonymity_combo, anonymity >= 0 ? anonymity : 1);
1822 1613
1823 gtk_entry_set_text (mctx->download_name_entry, filename != NULL ? filename : NULL); 1614 gtk_entry_set_text (mctx->download_name_entry, filename != NULL ? filename : NULL);
1824 gtk_file_chooser_set_current_folder (mctx->download_location_chooser, download_directory); 1615 gtk_file_chooser_set_current_folder (mctx->download_location_chooser, download_directory);
1825 1616
1826 gtk_widget_show_all (GTK_WIDGET (mctx->download_panel)); 1617 gtk_widget_show_all (GTK_WIDGET (mctx->download_panel));
1827 GNUNET_free (filename); 1618 GNUNET_free_non_null (filename);
1828 GNUNET_free (download_directory); 1619 GNUNET_free (download_directory);
1620 }
1621 else
1622 gtk_widget_hide (GTK_WIDGET (mctx->download_panel));
1623 if (current_selected_search_result != NULL)
1624 gtk_tree_path_free (current_selected_search_result);
1625 current_selected_search_result = selpath;
1829 } 1626 }
1830 else 1627 else
1831 gtk_widget_hide (GTK_WIDGET (mctx->download_panel)); 1628 gtk_tree_path_free (selpath);
1629
1832 1630
1833 if (NULL != pixbuf) 1631 if (NULL != pixbuf)
1834 { 1632 {
@@ -1880,6 +1678,9 @@ GNUNET_GTK_main_window_notebook_switch_page_cb (GtkWidget * dummy,
1880 clear meta data and preview widgets */ 1678 clear meta data and preview widgets */
1881 gtk_image_clear (mctx->preview_image); 1679 gtk_image_clear (mctx->preview_image);
1882 gtk_list_store_clear (mctx->md_liststore); 1680 gtk_list_store_clear (mctx->md_liststore);
1681 if (current_selected_search_result != NULL)
1682 gtk_tree_path_free (current_selected_search_result);
1683 current_selected_search_result = NULL;
1883} 1684}
1884 1685
1885 1686
@@ -2122,7 +1923,6 @@ update_search_result (struct SearchResult *sr,
2122 GNUNET_break (0); 1923 GNUNET_break (0);
2123 return; 1924 return;
2124 } 1925 }
2125 gtk_tree_path_free (tp);
2126 desc = GNUNET_FS_GTK_get_description_from_metadata (meta, &desc_is_a_dup); 1926 desc = GNUNET_FS_GTK_get_description_from_metadata (meta, &desc_is_a_dup);
2127 mime = get_mimetype_from_metadata (meta); 1927 mime = get_mimetype_from_metadata (meta);
2128 pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta); 1928 pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta);
@@ -2157,10 +1957,20 @@ update_search_result (struct SearchResult *sr,
2157 page = gtk_notebook_get_current_page (mctx->notebook); 1957 page = gtk_notebook_get_current_page (mctx->notebook);
2158 if (gtk_notebook_get_nth_page (mctx->notebook, page) == sr->tab->frame) 1958 if (gtk_notebook_get_nth_page (mctx->notebook, page) == sr->tab->frame)
2159 { 1959 {
2160 tv = GTK_TREE_VIEW (gtk_builder_get_object 1960 GtkTreeSelection *sel;
2161 (sr->tab->builder, "_search_result_frame")); 1961 GtkTreeModel *model;
2162 GNUNET_FS_GTK_search_treeview_cursor_changed (tv, sr->tab); 1962 GtkTreeIter iter;
1963 tv = GTK_TREE_VIEW (gtk_builder_get_object (sr->tab->builder, "_search_result_frame"));
1964 sel = gtk_tree_view_get_selection (tv);
1965 if (gtk_tree_selection_get_selected (sel, &model, &iter))
1966 {
1967 GtkTreePath *selpath = gtk_tree_model_get_path (model, &iter);
1968 if (gtk_tree_path_compare (selpath, tp) == 0)
1969 GNUNET_FS_GTK_search_treeview_cursor_changed (tv, sr->tab);
1970 gtk_tree_path_free (selpath);
1971 }
2163 } 1972 }
1973 gtk_tree_path_free (tp);
2164} 1974}
2165 1975
2166 1976
@@ -2313,6 +2123,85 @@ GNUNET_GTK_add_search_result (struct SearchTab *tab,
2313 2123
2314 2124
2315/** 2125/**
2126 * Sets downloaded name on an item referenced by @rr
2127 * in a tree store @ts to @filename.
2128 * Used by SaveAs dialog to communicate back new filename
2129 * (unless SaveAs dialog initiates the download by itself).
2130 * Arguments can be taken from DownloadEntry.
2131 *
2132 * @param ts treestore
2133 * @param rr row reference
2134 * @param filename new filename
2135 */
2136void
2137GNUNET_FS_GTK_set_item_downloaded_name (GtkTreeStore *ts, GtkTreeRowReference *rr, gchar *filename)
2138{
2139 struct GNUNET_GTK_MainWindowContext *mctx = GNUNET_FS_GTK_get_main_context ();
2140 GtkTreeIter iter;
2141 GtkTreePath *path;
2142
2143 path = gtk_tree_row_reference_get_path (rr);
2144 if (path)
2145 {
2146 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (ts), &iter, path))
2147 {
2148 /* TODO: maybe create a new store slot for user-defined filenames?
2149 * Also - maybe separate slots for downloaddir and relative filename?
2150 */
2151 /* This code relies on download panel contents being re-populated every 0.2 seconds,
2152 * thus it updates the treestore item property, from which suggested filename
2153 * is derived.
2154 */
2155 /*
2156 char *download_directory;
2157 char *suggested_filename;
2158 int anonymity = -1;
2159
2160 gtk_tree_store_set (ts, &iter, SEARCH_TAB_MC_DOWNLOADED_FILENAME, filename, -1);
2161
2162 download_directory = NULL;
2163 suggested_filename = get_suggested_filename_anonymity2 (GTK_TREE_MODEL (ts), &iter,
2164 &download_directory, &anonymity);
2165
2166 gtk_entry_set_text (mctx->download_name_entry, suggested_filename != NULL ? suggested_filename : NULL);
2167 gtk_file_chooser_set_current_folder (mctx->download_location_chooser, download_directory);
2168
2169 GNUNET_free_non_null (suggested_filename);
2170 GNUNET_free (download_directory);
2171 */
2172 /* This code relies on download panel contents NOT being re-populated every 0.2 seconds,
2173 * thus it only updates download panel contents - these changes will be lost after
2174 * selecting a different item and then coming back to this one.
2175 */
2176 gchar *current = g_strdup (filename);
2177 gchar *dirname = NULL;
2178 /* We take the filename user gave us, then check its parent directories until
2179 * we find one that actually exists (SaveAs dialog might have some options about
2180 * only picking existing names, but better be safe.
2181 * gtk_file_chooser_set_current_folder() does NOT work with non-existing dirnames!
2182 */
2183 do
2184 {
2185 dirname = g_path_get_dirname (current);
2186 g_free (current);
2187 if (g_file_test (dirname, G_FILE_TEST_EXISTS))
2188 {
2189 gchar *relname = &filename[strlen (dirname)];
2190 while (relname[0] == '/' || relname[0] == '\\')
2191 relname++;
2192 gtk_entry_set_text (mctx->download_name_entry, relname);
2193 gtk_file_chooser_set_current_folder (mctx->download_location_chooser, dirname);
2194 break;
2195 }
2196 current = dirname;
2197 } while (dirname[0] != '.'); /* FIXME: Check that this condition is correct */
2198 g_free (dirname);
2199 }
2200 gtk_tree_path_free (path);
2201 }
2202}
2203
2204/**
2316 * We have received a search result from the FS API. Add it to the 2205 * We have received a search result from the FS API. Add it to the
2317 * respective search tab. The search result can be an 'inner' 2206 * respective search tab. The search result can be an 'inner'
2318 * search result (updated result for a namespace search) or a 2207 * search result (updated result for a namespace search) or a