application/davcontroller.c

changeset 87
5360027fb282
parent 86
8e7c57c23133
equal deleted inserted replaced
86:8e7c57c23133 87:5360027fb282
30 #include "window.h" 30 #include "window.h"
31 31
32 #include <cx/printf.h> 32 #include <cx/printf.h>
33 33
34 #include "config.h" 34 #include "config.h"
35 #include "upload.h"
36 #include "download.h"
35 37
36 #include "system.h" 38 #include "system.h"
37 #include "common/context.h" 39 #include "common/context.h"
38 40
39 #include <libidav/config.h> 41 #include <libidav/config.h>
440 ui_set(browser->path, nav_url); 442 ui_set(browser->path, nav_url);
441 } 443 }
442 } 444 }
443 445
444 446
445 // ------------------------------------- File Upload -------------------------------------
446
447 typedef struct DavFileUpload {
448 UiObject *ui;
449 DavBrowser *browser;
450 DavSession *sn;
451 UiFileList files;
452 char *base_path;
453 UiThreadpool *queue;
454
455 size_t total_bytes;
456 size_t total_files;
457 size_t total_directories;
458 size_t uploaded_bytes;
459 size_t uploaded_files;
460 size_t uploaded_directories;
461
462 DavBool upload_file;
463 size_t current_file_size;
464 size_t current_file_upload;
465
466 char *current_file_name;
467
468 UiObject *dialog;
469 UiDouble *progress;
470 UiString *label_top_left;
471 UiString *label_top_right;
472 UiString *label_bottom_left;
473 UiString *label_bottom_right;
474
475 // The collection, the files are uploaded to
476 // It is only safe to access the collection ptr, if
477 // collection == browser->current && collection_ctn == browser->res_counter
478 // and obviously it can only be accessed from the UI thread
479 DavResource *collection;
480
481 // copy of browser->res_counter, used for integrity check
482 int64_t collection_ctn;
483
484 // current uploaded resource, created as part of the browser session
485 // only if collection == browser->current && collection_ctn == browser->res_counter
486 DavResource *current_resource;
487 } DavFileUpload;
488
489 typedef struct DUFile {
490 char *path;
491 char *upload_path;
492 size_t bytes;
493 DavBool isdirectory;
494 DavFileUpload *upload;
495 DavError error;
496 } DUFile;
497
498 static double upload_progress(DavFileUpload *upload) {
499 return ((double)upload->uploaded_bytes / (double)upload->total_bytes) * 100;
500 }
501
502 static void update_upload_labels(DavFileUpload *upload) {
503 char *sz_total = util_size_str(FALSE, upload->total_bytes);
504 char *sz_uploaded = util_size_str2(FALSE, upload->uploaded_bytes, upload->total_bytes, 2);
505 char *sz_uploaded_end = strchr(sz_uploaded, ' ');
506 if (sz_uploaded_end) {
507 *sz_uploaded_end = 0;
508 }
509
510 double progress = upload_progress(upload);
511 ui_set(upload->progress, upload_progress(upload));
512
513 cxmutstr label1;
514 if (upload->total_files + upload->total_directories > 1) {
515 label1 = cx_asprintf(
516 "%s/%s %zu/%zu files",
517 sz_uploaded,
518 sz_total,
519 upload->uploaded_files+upload->uploaded_directories,
520 upload->total_files+upload->total_directories);
521 } else {
522 label1 = cx_asprintf(
523 "%s/%s",
524 sz_uploaded,
525 sz_total);
526 }
527 ui_set(upload->label_top_left, label1.ptr);
528
529 free(sz_total);
530 free(label1.ptr);
531
532 if (upload->current_file_size > 0) {
533 cxmutstr file_label = cx_asprintf("%s (%.0f%%)", upload->current_file_name, ((float)upload->current_file_upload/(float)upload->current_file_size)*100);
534 ui_set(upload->label_top_right, file_label.ptr);
535 free(file_label.ptr);
536 }
537 }
538
539 static int uithr_update_upload_labels(void *data) {
540 update_upload_labels(data);
541 return 0;
542 }
543
544 static void upload_dav_progress(DavResource *res, int64_t total, int64_t now, void *data) {
545 DavFileUpload *upload = data;
546 if (upload->upload_file) {
547 if (now > upload->current_file_size) {
548 // current_file_size is not accurate (either the file was changed after the last stat
549 // or we have some extra bytes because of encryption
550 // adjust current_file_size and the total upload size
551 int64_t extra = now - upload->current_file_size;
552 upload->current_file_size += extra;
553 upload->total_bytes += extra;
554 }
555
556 int64_t new_progress = now - upload->current_file_upload;
557 upload->uploaded_bytes += new_progress;
558 upload->current_file_upload = now;
559
560 ui_call_mainthread(uithr_update_upload_labels, upload);
561 }
562 }
563
564
565 typedef struct FileNameUpdate {
566 DavFileUpload *upload;
567 char *name;
568 char *path;
569 DavBool iscollection;
570 } FileNameUpdate;
571
572 static int uithr_update_file_label(FileNameUpdate *update) {
573 // replace upload->current_filename with update->name
574 if (update->upload->current_file_name) {
575 free(update->upload->current_file_name);
576 }
577 update->upload->current_file_name = update->name;
578
579 ui_set(update->upload->label_top_right, update->name);
580
581 DavFileUpload *upload = update->upload;
582 DavBrowser *browser = upload->browser;
583 // update the resource list in the browser, if the current collection has not changed
584 if (upload->collection == browser->current && upload->collection_ctn == browser->res_counter) {
585 char *parent = util_parent_path(update->path);
586 cxstring parent_s = cx_str(parent);
587 cxstring colpath_s = cx_str(upload->collection->path);
588 if (parent_s.length > 0 && parent_s.ptr[parent_s.length - 1] == '/') {
589 parent_s.length--;
590 }
591 if (colpath_s.length > 0 && colpath_s.ptr[colpath_s.length - 1] == '/') {
592 colpath_s.length--;
593 }
594
595 // only update, if the added resource has the current collection as parent
596 if (!cx_strcmp(parent_s, colpath_s)) {
597 DavResource *ui_res = dav_resource_new(upload->collection->session, update->path);
598 ui_res->iscollection = update->iscollection;
599 ui_res->lastmodified = time(NULL);
600 ui_res->creationdate = time(NULL);
601 upload->current_resource = ui_res;
602
603 ui_list_append(browser->resources, ui_res);
604 browser->resources->update(browser->resources, 0);
605 } else {
606 upload->current_resource = NULL; // maybe not necessary
607 }
608 free(parent);
609 }
610
611 free(update->path);
612 free(update);
613 return 0;
614 }
615
616 static int qthr_file_upload(void *data) {
617 DUFile *f = data;
618 DavFileUpload *upload = f->upload;
619 DavSession *sn = upload->sn;
620
621 FILE *in = sys_fopen(f->path, "rb");
622 if (!in) {
623 // TODO: error msg
624 return 0;
625 }
626
627 upload->upload_file = TRUE;
628 upload->current_file_size = f->bytes;
629 upload->current_file_upload = 0;
630
631 DavResource *res = dav_resource_new(sn, f->upload_path);
632
633 FileNameUpdate *ui_update = malloc(sizeof(FileNameUpdate));
634 ui_update->upload = upload;
635 ui_update->name = strdup(res->name);
636 ui_update->path = strdup(res->path);
637 ui_update->iscollection = FALSE;
638 ui_call_mainthread((ui_threadfunc)uithr_update_file_label, ui_update);
639
640 dav_set_content(res, in, (dav_read_func)fread, (dav_seek_func)fseek);
641 if (dav_store(res)) {
642 f->error = sn->error;
643 }
644 dav_resource_free(res);
645
646 fclose(in);
647
648 upload->upload_file = FALSE;
649
650 return 0;
651 }
652
653 static void uithr_file_uploaded(UiEvent *event, void *data) {
654 DUFile *file = data;
655 DavFileUpload *upload = file->upload;
656
657 upload->uploaded_files++;
658 //upload->uploaded_bytes += file->bytes;
659
660 double progress = upload_progress(upload);
661 ui_set(upload->progress, upload_progress(upload));
662
663 update_upload_labels(upload);
664
665 // update resource content length in the browser
666 DavBrowser *browser = upload->browser;
667 if (upload->collection == browser->current && upload->collection_ctn == browser->res_counter) {
668 if (upload->current_resource) {
669 upload->current_resource->contentlength = upload->current_file_upload;
670 browser->resources->update(browser->resources, 0);
671 }
672 }
673 upload->current_resource = NULL;
674
675 free(file->path);
676 free(file->upload_path);
677 }
678
679 static int qthr_dir_upload(void *data) {
680 DUFile *f = data;
681 DavFileUpload *upload = f->upload;
682 DavSession *sn = upload->sn;
683
684 DavResource *res = dav_resource_new(sn, f->upload_path);
685 res->iscollection = TRUE;
686
687 FileNameUpdate *ui_update = malloc(sizeof(FileNameUpdate));
688 ui_update->upload = upload;
689 ui_update->name = strdup(res->name);
690 ui_update->path = strdup(res->path);
691 ui_update->iscollection = TRUE;
692 ui_call_mainthread((ui_threadfunc)uithr_update_file_label, ui_update);
693
694 if (dav_create(res)) {
695 f->error = sn->error;
696 }
697
698 dav_resource_free(res);
699
700 return 0;
701 }
702
703 static void uithr_dir_uploaded(UiEvent *event, void *data) {
704 DUFile *file = data;
705 DavFileUpload *upload = file->upload;
706
707 upload->uploaded_directories++;
708
709 update_upload_labels(upload);
710
711 upload->current_resource = NULL;
712
713 free(file->path);
714 free(file->upload_path);
715 }
716
717 static int qthr_upload_finished(void *data) {
718 return 0;
719 }
720
721 static void uithr_upload_finished(UiEvent *event, void *data) {
722 DavFileUpload *upload = data;
723 ui_threadpool_destroy(upload->queue);
724
725 free(upload->base_path);
726 dav_session_destroy(upload->sn);
727 }
728
729 static int jobthr_upload_scan(void *data) {
730 DavFileUpload *upload = data;
731
732 CxList *stack = cxLinkedListCreateSimple(CX_STORE_POINTERS);
733 for (int i = 0; i < upload->files.nfiles; i++) {
734 DUFile *f = malloc(sizeof(DUFile));
735 f->path = strdup(upload->files.files[i]);
736 f->upload_path = util_concat_path(upload->base_path, util_path_file_name(f->path));
737 f->isdirectory = FALSE;
738 f->bytes = 0;
739 f->upload = upload;
740 f->error = 0;
741 cxListInsert(stack, 0, f);
742 }
743
744 while (cxListSize(stack) > 0) {
745 DUFile *f = cxListAt(stack, 0);
746
747 char *path = util_concat_path(upload->base_path, f->upload_path);
748 cxListRemove(stack, 0);
749
750 SYS_STAT s;
751 if (!sys_stat(f->path, &s)) {
752 if (S_ISDIR(s.st_mode)) {
753 f->isdirectory = TRUE;
754 upload->total_directories++;
755 ui_threadpool_job(upload->queue, upload->ui, qthr_dir_upload, f, uithr_dir_uploaded, f);
756
757 SYS_DIR dir = sys_opendir(f->path);
758 if (dir) {
759 SysDirEnt *entry;
760 int nument = 0;
761 while((entry = sys_readdir(dir)) != NULL) {
762 if(!strcmp(entry->name, ".") || !strcmp(entry->name, "..")) {
763 continue;
764 }
765
766 cxmutstr newpath = util_concat_sys_path(cx_str(f->path), cx_str(entry->name));
767 char *new_upload_path = util_concat_path(f->upload_path, entry->name);
768
769 DUFile *child = malloc(sizeof(DUFile));
770 child->path = newpath.ptr;
771 child->upload_path = new_upload_path;
772 child->isdirectory = FALSE;
773 child->bytes = 0;
774 child->upload = upload;
775 child->error = 0;
776 cxListAdd(stack, child);
777 }
778
779 sys_closedir(dir);
780 }
781 } else if (S_ISREG(s.st_mode)) {
782 f->isdirectory = FALSE;
783 f->bytes = s.st_size;
784 upload->total_files++;
785 upload->total_bytes += s.st_size;
786 ui_threadpool_job(upload->queue, upload->ui, qthr_file_upload, f, uithr_file_uploaded, f);
787 }
788 }
789 } // TODO: else error msg
790
791 ui_threadpool_job(upload->queue, upload->ui, qthr_upload_finished, upload, uithr_upload_finished, upload);
792
793 ui_filelist_free(upload->files);
794
795 return 0;
796 }
797
798 static void uithr_upload_scan_finished(UiEvent *event, void *data) {
799 DavFileUpload *upload = data;
800
801 update_upload_labels(upload);
802 }
803
804 static void upload_window_closed(UiEvent *event, void *data) {
805 // noop, prevents context destruction
806 }
807
808 void davbrowser_upload_files(UiObject *ui, DavBrowser *browser, UiFileList files) { 447 void davbrowser_upload_files(UiObject *ui, DavBrowser *browser, UiFileList files) {
809 if (!browser->sn) { 448 if (!browser->sn) {
810 return; // TODO: error msg 449 return; // TODO: error msg
811 } 450 }
812 451
813 // we need a clone of the current session, because the upload
814 // is done in a separate thread
815 DavSession *upload_session = dav_session_clone(browser->sn);
816
817 // create upload obj, that contains all relevant data for the upload
818 DavFileUpload *upload = malloc(sizeof(DavFileUpload));
819 memset(upload, 0, sizeof(DavFileUpload));
820
821 dav_session_set_progresscallback(upload_session, NULL, upload_dav_progress, upload);
822
823 upload->ui = ui;
824 upload->browser = browser;
825 upload->sn = upload_session;
826 upload->files = files;
827 upload->base_path = strdup(browser->current->path);
828 upload->queue = ui_threadpool_create(1);
829
830 upload->collection = browser->current;
831 upload->collection_ctn = browser->res_counter;
832
833 // create upload progress window
834 cxmutstr wtitle = cx_asprintf("Upload to: %s", ui_get(browser->path)); 452 cxmutstr wtitle = cx_asprintf("Upload to: %s", ui_get(browser->path));
835 UiObject *dialog = ui_simple_window(wtitle.ptr, upload); 453 UiObject *dialog = ui_simple_window(wtitle.ptr, NULL);
836 ui_context_closefunc(dialog->ctx, upload_window_closed, NULL);
837 free(wtitle.ptr); 454 free(wtitle.ptr);
838 upload->dialog = dialog; 455
839 ui_window_size(dialog, 550, 120); 456 DavFileUpload *upload = dav_upload_create(browser, dialog, files);
840 upload->progress = ui_double_new(dialog->ctx, NULL); 457 transfer_window_init(dialog, action_upload_cancel);
841 upload->label_top_left = ui_string_new(dialog->ctx, NULL); 458 dav_upload_start(upload);
842 upload->label_top_right = ui_string_new(dialog->ctx, NULL); 459 }
843 upload->label_bottom_left = ui_string_new(dialog->ctx, NULL);
844 upload->label_bottom_right = ui_string_new(dialog->ctx, NULL);
845
846 ui_grid(dialog, .margin = 10, .spacing = 10, .fill = TRUE) {
847 ui_llabel(dialog, .value = upload->label_top_left, .hexpand = TRUE);
848 ui_rlabel(dialog, .value = upload->label_top_right);
849 ui_newline(dialog);
850
851 ui_progressbar(dialog, .value = upload->progress, .colspan = 2, .hexpand = TRUE);
852 ui_newline(dialog);
853
854 ui_llabel(dialog, .value = upload->label_bottom_left);
855 ui_rlabel(dialog, .value = upload->label_bottom_right);
856 ui_newline(dialog);
857 }
858
859 ui_set(upload->label_top_left, "");
860 ui_set(upload->label_top_right, "");
861 ui_set(upload->label_bottom_left, "");
862 ui_set(upload->label_bottom_right, "");
863 ui_set(upload->progress, 0);
864
865 ui_show(dialog);
866
867 // start upload and stat threads
868 ui_job(ui, jobthr_upload_scan, upload, uithr_upload_scan_finished, upload);
869 }
870
871
872 // ------------------------------------- File Download -------------------------------------
873
874 typedef struct DavFileDownload {
875 UiObject *ui;
876 DavBrowser *browser;
877
878 DavSession *sn;
879 DavSession *download_sn;
880 DavResource *reslist;
881 char *local_path;
882 DavBool isdirectory;
883
884 UiThreadpool *queue;
885
886 size_t total_bytes;
887 size_t total_files;
888 size_t total_directories;
889 size_t downloaded_bytes;
890 size_t downloaded_files;
891 size_t downloaded_directories;
892
893 size_t current_file_size;
894 size_t current_file_downloaded;
895
896 UiObject *dialog;
897 UiDouble *progress;
898 UiString *label_top_left;
899 UiString *label_top_right;
900 UiString *label_bottom_left;
901 UiString *label_bottom_right;
902 } DavFileDownload;
903
904
905 static int uithr_download_update_progress(void *data) {
906 DavFileDownload *download = data;
907 char *sz_total = util_size_str(FALSE, download->total_bytes);
908 char *sz_downloaded = util_size_str2(FALSE, download->downloaded_bytes, download->total_bytes, 2);
909 char *sz_downloaded_end = strchr(sz_downloaded, ' ');
910 if (sz_downloaded_end) {
911 *sz_downloaded_end = 0;
912 }
913
914 if (download->total_bytes > 0) {
915 double progress = (double)download->downloaded_bytes / (double)download->total_bytes;
916 ui_set(download->progress, progress*100);
917 }
918
919
920 cxmutstr label1;
921 if (download->total_files + download->total_directories > 1) {
922 label1 = cx_asprintf(
923 "%s/%s %zu/%zu files",
924 sz_downloaded,
925 sz_total,
926 download->downloaded_files+download->downloaded_directories,
927 download->total_files+download->total_directories);
928 } else {
929 label1 = cx_asprintf(
930 "%s/%s",
931 sz_downloaded,
932 sz_total);
933 }
934 ui_set(download->label_top_left, label1.ptr);
935
936 free(sz_total);
937 free(label1.ptr);
938
939
940 return 1;
941 }
942
943 // dav download file
944 typedef struct DDFile {
945 DavFileDownload *download;
946 size_t size;
947 char *path;
948 char *to;
949 FILE *fd;
950 } DDFile;
951
952 static size_t ddfile_write(const void *buf, size_t size, size_t count, void *stream) {
953 DDFile *file = stream;
954
955 size_t w = fwrite(buf, size, count, file->fd);
956 file->download->current_file_downloaded += w;
957
958 file->download->downloaded_bytes += w;
959
960 if (file->download->current_file_downloaded > file->download->current_file_size) {
961 size_t diff = file->download->current_file_downloaded - file->download->current_file_size;
962 file->download->current_file_size = file->download->current_file_downloaded;
963 file->download->total_bytes += diff;
964 }
965
966 ui_call_mainthread(uithr_download_update_progress, file->download);
967
968 return w;
969 }
970
971 static int qthr_download_resource(void *data) {
972 DDFile *file = data;
973
974 file->download->current_file_downloaded = 0;
975 file->download->current_file_size = file->size;
976
977 FILE *f = sys_fopen(file->to, "wb");
978 if (!f) {
979 return 0;
980 }
981 file->fd = f;
982
983 DavResource *res = dav_resource_new(file->download->download_sn, file->path);
984 dav_get_content(res, file, (dav_write_func)ddfile_write);
985
986 file->download->downloaded_files++;
987
988 ui_call_mainthread(uithr_download_update_progress, file->download);
989
990 dav_resource_free(res);
991
992 fclose(f);
993
994 free(file->path);
995 free(file->to);
996 free(file);
997
998 return 0;
999 }
1000
1001 static int qthr_download_finished(void *data) {
1002 return 0;
1003 }
1004
1005 static void uithr_download_finished(UiEvent *event, void *data) {
1006 DavFileDownload *download = data;
1007 printf("download finished\n");
1008 ui_object_unref(download->dialog);
1009 }
1010
1011
1012 typedef struct DlStackElm {
1013 DavResource *resource;
1014 char *sub_path;
1015 } DlStackElm;
1016
1017 static int jobthr_download_scan(void *data) {
1018 DavFileDownload *download = data;
1019 DavBrowser *browser = download->browser;
1020
1021 // check if the specified local location is a directory
1022 SYS_STAT s;
1023 if (!sys_stat(download->local_path, &s)) {
1024 if (S_ISDIR(s.st_mode)) {
1025 download->isdirectory = TRUE;
1026 }
1027 }
1028
1029 CxList *stack = cxLinkedListCreateSimple(sizeof(DlStackElm));
1030
1031 // add selected files to the download queue
1032 DavResource *res = download->reslist;
1033 while (res) {
1034 DlStackElm elm;
1035 elm.resource = res;
1036 elm.sub_path = strdup(res->name);
1037 cxListAdd(stack, &elm);
1038
1039 res = res->next;
1040 }
1041
1042 while (cxListSize(stack) > 0) {
1043 DlStackElm *elm = cxListAt(stack, 0);
1044 DavResource *res = elm->resource;
1045 char *sub_path = elm->sub_path;
1046 cxListRemove(stack, 0);
1047
1048 if (res->iscollection) {
1049 if (dav_load(res)) {
1050 // TODO: handle error
1051 continue;
1052 }
1053
1054 // update ui
1055 ui_call_mainthread(uithr_download_update_progress, download);
1056
1057 char *path = util_concat_path(download->local_path, sub_path);
1058 int err = sys_mkdir(path);
1059 free(path);
1060 if (err) {
1061 // TODO: handle error
1062 }
1063
1064 DavResource *child = res->children;
1065 while (child) {
1066 char *child_path = util_concat_path(sub_path, child->name);
1067 DlStackElm childelm;
1068 childelm.resource = child;
1069 childelm.sub_path = child_path;
1070 cxListAdd(stack, &childelm);
1071
1072 child = child->next;
1073 }
1074 } else {
1075 // add the file to the download queue
1076 DDFile *file = malloc(sizeof(DDFile));
1077 file->download = download;
1078 file->path = strdup(res->path);
1079 file->size = res->contentlength;
1080 if (download->isdirectory) {
1081 file->to = util_concat_path(download->local_path, sub_path);
1082 } else {
1083 file->to = strdup(download->local_path);
1084 }
1085
1086 // stats
1087 download->total_files++;
1088 download->total_bytes += res->contentlength;
1089
1090 // update ui
1091 ui_call_mainthread(uithr_download_update_progress, download);
1092
1093 ui_threadpool_job(download->queue, download->ui, qthr_download_resource, file, NULL, NULL);
1094 }
1095 }
1096
1097 ui_threadpool_job(download->queue, download->ui, qthr_download_finished, download, uithr_download_finished, download);
1098
1099 cxListDestroy(stack);
1100
1101 return 0;
1102 }
1103
1104 static void uithr_download_scan_finished(UiEvent *event, void *data) {
1105 DavFileDownload *download = data;
1106
1107 }
1108
1109 static void download_window_closed(UiEvent *event, void *data) {
1110
1111 }
1112
1113 460
1114 void davbrowser_download(UiObject *ui, DavBrowser *browser, DavResource *reslist, const char *local_path) { 461 void davbrowser_download(UiObject *ui, DavBrowser *browser, DavResource *reslist, const char *local_path) {
1115 DavFileDownload *download = malloc(sizeof(DavFileDownload));
1116 memset(download, 0, sizeof(DavFileDownload));
1117
1118 download->ui = ui;
1119 download->browser = browser;
1120 download->sn = reslist->session;
1121 download->download_sn = dav_session_clone(download->sn);
1122 download->reslist = reslist; // TODO: is this safe or do we need a copy?
1123 download->local_path = strdup(local_path);
1124
1125 download->queue = ui_threadpool_create(1);
1126
1127 // create download progress window
1128 cxmutstr wtitle = cx_asprintf("Download to: %s", local_path); 462 cxmutstr wtitle = cx_asprintf("Download to: %s", local_path);
1129 UiObject *dialog = ui_simple_window(wtitle.ptr, download); 463 UiObject *dialog = ui_simple_window(wtitle.ptr, NULL);
1130 ui_context_closefunc(dialog->ctx, download_window_closed, NULL);
1131 free(wtitle.ptr); 464 free(wtitle.ptr);
1132 download->dialog = dialog; 465
1133 ui_window_size(dialog, 550, 120); 466 DavFileDownload *download = dav_download_create(browser, dialog, reslist, local_path);
1134 download->progress = ui_double_new(dialog->ctx, NULL); 467 transfer_window_init(dialog, action_download_cancel);
1135 download->label_top_left = ui_string_new(dialog->ctx, NULL); 468 dav_download_start(download);
1136 download->label_top_right = ui_string_new(dialog->ctx, NULL);
1137 download->label_bottom_left = ui_string_new(dialog->ctx, NULL);
1138 download->label_bottom_right = ui_string_new(dialog->ctx, NULL);
1139
1140 ui_grid(dialog, .margin = 10, .spacing = 10, .fill = TRUE) {
1141 ui_llabel(dialog, .value = download->label_top_left, .hexpand = TRUE);
1142 ui_rlabel(dialog, .value = download->label_top_right);
1143 ui_newline(dialog);
1144
1145 ui_progressbar(dialog, .value = download->progress, .min = 0, .max = 100, .colspan = 2, .hexpand = TRUE);
1146 ui_newline(dialog);
1147
1148 ui_llabel(dialog, .value = download->label_bottom_left);
1149 ui_rlabel(dialog, .value = download->label_bottom_right);
1150 ui_newline(dialog);
1151 }
1152
1153 ui_set(download->label_top_left, "");
1154 ui_set(download->label_top_right, "");
1155 ui_set(download->label_bottom_left, "");
1156 ui_set(download->label_bottom_right, "");
1157 ui_set(download->progress, 0);
1158
1159 ui_show(dialog);
1160
1161 ui_object_ref(dialog);
1162
1163 // start upload and stat threads
1164 ui_job(ui, jobthr_download_scan, download, uithr_download_scan_finished, download);
1165 } 469 }
1166 470
1167 471
1168 // ------------------------------------- Path Operation (DELETE, MKCOL) ------------------------------------- 472 // ------------------------------------- Path Operation (DELETE, MKCOL) -------------------------------------
1169 473

mercurial