diff options
Diffstat (limited to 'src/fs/gnunet-fs-gtk_event-handler.c')
-rw-r--r-- | src/fs/gnunet-fs-gtk_event-handler.c | 627 |
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; | |||
262 | static struct PublishTab *publish_tab; | 262 | static struct PublishTab *publish_tab; |
263 | 263 | ||
264 | /** | 264 | /** |
265 | * Special tab we use to store publishing operations. | 265 | * Currently displayed search tab |
266 | */ | 266 | */ |
267 | static struct SearchTab *current_search_tab = NULL; | 267 | static struct SearchTab *current_search_tab = NULL; |
268 | 268 | ||
269 | /** | 269 | /** |
270 | * Currently selected row in a search tab. | ||
271 | */ | ||
272 | static GtkTreePath *current_selected_search_result = NULL; | ||
273 | |||
274 | /** | ||
270 | * Animation to display while publishing. | 275 | * Animation to display while publishing. |
271 | */ | 276 | */ |
272 | static struct GNUNET_FS_AnimationContext *animation_publishing; | 277 | static 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 | */ | ||
412 | static char * | ||
413 | get_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 | */ | ||
634 | static char * | 540 | static char * |
635 | get_suggested_filename_anonymity2 (GtkTreeModel *tm, | 541 | get_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 | */ | ||
718 | static void | ||
719 | start_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 | */ |
845 | struct SearchListPopupContext | 619 | struct 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 | */ | ||
893 | void | ||
894 | GNUNET_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 | */ | ||
936 | static void | ||
937 | start_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 | */ | ||
967 | static void | 674 | static void |
968 | start_download2 () | 675 | start_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 | */ | ||
776 | static void | ||
777 | start_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 | */ | ||
794 | void | ||
795 | GNUNET_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 | |||
1052 | GNUNET_GTK_search_frame_download_download_button_clicked_cb ( | 811 | GNUNET_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 | */ | ||
824 | void | ||
825 | GNUNET_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 | */ |
1095 | static void | 868 | static void |
1096 | start_download_as_ctx_menu (GtkMenuItem *item, gpointer user_data) | 869 | download_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 | */ | ||
2136 | void | ||
2137 | GNUNET_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 |