add upload/download list, resolves #512

Wed, 27 Nov 2024 18:45:08 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 27 Nov 2024 18:45:08 +0100
changeset 95
e92c72705da4
parent 94
7fdf1489b82f
child 96
493959648de6

add upload/download list, resolves #512

application/application.c file | annotate | diff | comparison | revisions
application/application.h file | annotate | diff | comparison | revisions
application/davcontroller.c file | annotate | diff | comparison | revisions
application/download.c file | annotate | diff | comparison | revisions
application/download.h file | annotate | diff | comparison | revisions
application/upload.c file | annotate | diff | comparison | revisions
application/upload.h file | annotate | diff | comparison | revisions
application/window.c file | annotate | diff | comparison | revisions
ui/common/types.c file | annotate | diff | comparison | revisions
ui/common/types.h file | annotate | diff | comparison | revisions
ui/gtk/menu.c file | annotate | diff | comparison | revisions
--- a/application/application.c	Wed Nov 27 17:14:57 2024 +0100
+++ b/application/application.c	Wed Nov 27 18:45:08 2024 +0100
@@ -113,6 +113,10 @@
             ui_menu_itemlist(.varname = "repolist", .getvalue = davrepo_getname, .onselect = action_repo_selected);
         }
     }
+    
+    ui_menu("View") {
+        ui_menu_itemlist(.varname = "transferlist", .getvalue = transfers_getlabel, .onselect = action_transfer_selected);
+    }
 
     // toolbar
     ui_toolbar_item("Home", .icon = UI_ICON_HOME);
@@ -138,6 +142,10 @@
         ui_menuitem("Open Properties", .onclick = action_open_properties, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION, APP_STATE_BROWSER_SELECTION));
         ui_menuitem("Open as Text File", .onclick = action_open_properties, .onclickdata = "text/plain", .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION, APP_STATE_BROWSER_SELECTION));
         ui_menuseparator();
+        ui_menu("Downloads/Uploads") {
+            ui_menu_itemlist(.varname = "transferlist", .getvalue = transfers_getlabel, .onselect = action_transfer_selected);
+        }
+        ui_menuseparator();
         ui_menuitem("Preferences", .onclick = action_open_settings);
     }
 
@@ -162,7 +170,10 @@
     DavApp *doc = ui_document_new(sizeof(DavApp));
     UiContext *ctx = ui_document_context(doc);
     doc->repos = ui_list_new(ctx, "repolist");
-
+    doc->transfers = ui_list_new(ctx, "transferlist");
+    CxList *transfers = doc->transfers->data;
+    transfers->collection.cmpfunc = cx_cmp_ptr;
+    
     // create repo list
     application_update_repolist(doc);
 
@@ -186,6 +197,44 @@
     return davctx;
 }
 
+void* transfers_getlabel(void *data, int col) {
+    DavTransfer *trans = data;
+    return trans->label;
+}
+
+void application_register_transfer(DavTransfer *trans) {
+    DavApp *app = get_application();
+    ui_list_append(app->transfers, trans);
+    application_update_transferlist();
+}
+
+void application_remove_transfer(DavTransfer *trans) {
+    DavApp *app = get_application();
+    CxList *transfers = app->transfers->data;
+    cxListFindRemove(transfers, trans);
+    application_update_transferlist();
+}
+
+/*
+static int transfers_cmp(const DavTransfer *left, const DavTransfer *right) {
+    return cx_cmp_double(&right->progress, &left->progress);
+}
+*/
+
+void application_update_transferlist(void) {
+    DavApp *app = get_application();
+    
+    /*
+    CxList *transfers = app->transfers->data;
+    transfers->collection.cmpfunc = (cx_compare_func)transfers_cmp;
+    cxListSort(transfers);
+    transfers->collection.cmpfunc = cx_cmp_ptr;
+    */
+    
+    ui_list_update(app->transfers);
+    ui_list_notify(app->transfers);
+}
+
 
 void action_window_new(UiEvent *event, void *data) {
     UiObject *win = window_create();
@@ -390,3 +439,7 @@
     }
     ui_listselection_free(sel);
 }
+
+void action_transfer_selected(UiEvent *event, void *data) {
+    
+}
--- a/application/application.h	Wed Nov 27 17:14:57 2024 +0100
+++ b/application/application.h	Wed Nov 27 18:45:08 2024 +0100
@@ -52,8 +52,17 @@
 typedef struct DavApp {
     DavConfig *dav_config;
     UiList *repos;
+    UiList *transfers;
 } DavApp;
 
+// download/upload
+typedef struct DavTransfer {
+    char *label;
+    size_t label_len;
+    double progress;
+    UiObject *window;
+    time_t last_update;
+} DavTransfer;
 
 typedef enum DavResourceViewType {
     DAV_RESOURCE_VIEW_PROPERTIES = 0,
@@ -67,6 +76,8 @@
  * main window document object
  */
 typedef struct DavBrowser {
+    UiObject *window;
+    
     UiContext *ctx;
     DavSession *sn;
     UiThreadpool *dav_queue;
@@ -162,6 +173,12 @@
 
 DavApp* get_application(void);
 
+void* transfers_getlabel(void *data, int col);
+
+void application_register_transfer(DavTransfer *trans);
+void application_remove_transfer(DavTransfer *trans);
+void application_update_transferlist(void);
+
 DavApp* application_create_app_document(void);
 
 void application_update_repolist(DavApp *app);
@@ -196,6 +213,8 @@
 
 void action_open_properties(UiEvent *event, void *data);
 
+void action_transfer_selected(UiEvent *event, void *data);
+
 #ifdef    __cplusplus
 }
 #endif
--- a/application/davcontroller.c	Wed Nov 27 17:14:57 2024 +0100
+++ b/application/davcontroller.c	Wed Nov 27 18:45:08 2024 +0100
@@ -44,6 +44,7 @@
 DavBrowser* davbrowser_create(UiObject *toplevel) {
     DavBrowser *doc = ui_document_new(sizeof(DavBrowser));
     UiContext *ctx = ui_document_context(doc);
+    doc->window = toplevel;
     doc->ctx = ctx;
 
     doc->navigation_stack = cxLinkedListCreateSimple(CX_STORE_POINTERS);
@@ -468,6 +469,7 @@
     DavFileUpload *upload = dav_upload_create(browser, dialog, files);
     transfer_window_init(dialog, action_upload_cancel);
     dav_upload_start(upload);
+    application_register_transfer(&upload->trans);
 }
 
 void davbrowser_download(UiObject *ui, DavBrowser *browser, DavResource *reslist, const char *local_path) {
@@ -478,6 +480,7 @@
     DavFileDownload *download = dav_download_create(browser, dialog, reslist, local_path);
     transfer_window_init(dialog, action_download_cancel);
     dav_download_start(download);
+    application_register_transfer(&download->trans);
 }
 
 
--- a/application/download.c	Wed Nov 27 17:14:57 2024 +0100
+++ b/application/download.c	Wed Nov 27 18:45:08 2024 +0100
@@ -48,6 +48,8 @@
         return 1;
     }
     
+    time_t t = time(NULL);
+    
     char *sz_total = util_size_str(FALSE, download->progress.total_bytes);
     char *sz_downloaded = util_size_str2(FALSE, download->progress.transferred_bytes, download->progress.total_bytes, 2);
     char *sz_downloaded_end = strchr(sz_downloaded, ' ');
@@ -56,8 +58,16 @@
     }
     
     if (download->progress.total_bytes > 0) {
-        double progress = (double)download->progress.transferred_bytes / (double)download->progress.total_bytes;
-        ui_set(download->progressbar, progress*100);
+        double progress = ((double)download->progress.transferred_bytes / (double)download->progress.total_bytes)*100;
+        ui_set(download->progressbar, progress);
+        download->trans.progress = progress;
+        /*
+        if(t > download->trans.last_update + 2) {
+            snprintf(download->trans.label+download->trans.label_len, 12, " %d%%", (int)progress);
+            application_update_transferlist();
+            download->trans.last_update = t;
+        }
+        */
     }
     
 
@@ -81,7 +91,6 @@
     free(label1.ptr);
     
     time_t start = download->progress.speedtest_start;
-    time_t t = time(NULL);
     if(t >= download->progress.speedtest_start + 4) {
         uint64_t bytesPerSeconds = dav_transfer_speed(&download->progress, t);
         if(start > 0) {
@@ -263,13 +272,6 @@
 
 }
 
-static void download_window_closed(UiEvent *event, void *data) {
-    DavFileDownload *download = event->obj->window;
-    
-    dav_session_destroy(download->sn);
-    ui_threadpool_destroy(download->queue);
-}
-
 void action_download_cancel(UiEvent *event, void *data) {
     DavFileDownload *download = event->window;
     if(!download->cancel) {
@@ -278,14 +280,25 @@
     }
 }
 
+static void dav_file_download_cleanup(DavFileDownload *download) {
+    application_remove_transfer(&download->trans);
+    ui_object_unref(download->browser->window);
+}
 
 DavFileDownload* dav_download_create(DavBrowser *browser, UiObject *dialog, DavResource *reslist, const char *local_path) {
     UiContext *ctx = dialog->ctx;
+    CxMempool *mp = ui_cx_mempool(ctx);
     DavFileDownload *download = ui_malloc(ctx, sizeof(DavFileDownload));
     memset(download, 0, sizeof(DavFileDownload));
     download->dialog = dialog;
     dialog->window = download;
     ui_object_ref(dialog);
+    ui_object_ref(browser->window);
+    
+    size_t label_len = strlen(reslist->name) + 16;
+    download->trans.label = cxCalloc(mp->allocator, label_len, 1);
+    download->trans.label_len = snprintf(download->trans.label, label_len, "< %s%s", reslist->name, reslist->next ? " ..." : "");
+    download->trans.window = dialog;
     
     download->browser = browser;
     download->sn = reslist->session;
@@ -295,9 +308,9 @@
 
     download->queue = ui_threadpool_create(1);
     
-    CxMempool *mp = ui_cx_mempool(ctx);
     cxMempoolRegister(mp, download->download_sn, (cx_destructor_func)dav_session_destroy);
     cxMempoolRegister(mp, download->queue, (cx_destructor_func)ui_threadpool_destroy);
+    cxMempoolSetDestructor(download, (cx_destructor_func)dav_file_download_cleanup);
     
     download->progressbar = ui_double_new(ctx, "progressbar");
     download->label_top_left = ui_string_new(ctx, "label_top_left");
--- a/application/download.h	Wed Nov 27 17:14:57 2024 +0100
+++ b/application/download.h	Wed Nov 27 18:45:08 2024 +0100
@@ -38,6 +38,7 @@
 
 
 typedef struct DavFileDownload {
+    DavTransfer trans;
     DavBrowser *browser;
 
     DavSession *sn;
--- a/application/upload.c	Wed Nov 27 17:14:57 2024 +0100
+++ b/application/upload.c	Wed Nov 27 18:45:08 2024 +0100
@@ -57,6 +57,15 @@
 
     double progress = upload_progress(upload);
     ui_set(upload->progressbar, progress);
+    upload->trans.progress = progress;
+    time_t t = time(NULL);
+    /*
+    if(t > upload->trans.last_update + 2) {
+        snprintf(upload->trans.label+upload->trans.label_len, 12, " %d%%", (int)progress);
+        application_update_transferlist();
+        upload->trans.last_update = t;
+    }
+    */
 
     cxmutstr label1;
     if (upload->progress.total_files + upload->progress.total_directories > 1) {
@@ -84,7 +93,6 @@
     }
     
     time_t start = upload->progress.speedtest_start;
-    time_t t = time(NULL);
     if(t >= upload->progress.speedtest_start + 4) {
         uint64_t bytesPerSeconds = dav_transfer_speed(&upload->progress, t);
         if(start > 0) {
@@ -407,13 +415,25 @@
     }
 }
 
+static void dav_file_upload_cleanup(DavFileUpload *upload) {
+    application_remove_transfer(&upload->trans);
+    ui_object_unref(upload->browser->window);
+}
+
 DavFileUpload* dav_upload_create(DavBrowser *browser, UiObject *obj, UiFileList files) {
     UiContext *ctx = obj->ctx;
+    CxMempool *mp = ui_cx_mempool(ctx);
     DavFileUpload *upload = ui_malloc(ctx, sizeof(DavFileUpload));
     memset(upload, 0, sizeof(DavFileUpload));
     upload->dialog = obj;
     obj->window = upload;
     ui_object_ref(obj);
+    ui_object_ref(browser->window);
+    
+    size_t label_len = strlen(util_resource_name(files.files[0])) + 16;
+    upload->trans.label = cxCalloc(mp->allocator, label_len, 1);
+    upload->trans.label_len = snprintf(upload->trans.label, label_len, "> %s%s", util_resource_name(files.files[0]), files.nfiles > 1 ? " ..." : "");
+    upload->trans.window = obj;
     
     upload->progressbar = ui_double_new(ctx, "progressbar");
     upload->label_top_left = ui_string_new(ctx, "label_top_left");
@@ -436,9 +456,9 @@
     upload->collection = browser->current;
     upload->collection_ctn = browser->res_counter;
     
-    CxMempool *mp = ui_cx_mempool(ctx);
     cxMempoolRegister(mp, upload_session, (cx_destructor_func)dav_session_destroy);
     cxMempoolRegister(mp, upload->queue, (cx_destructor_func)ui_threadpool_destroy);
+    cxMempoolSetDestructor(upload, (cx_destructor_func)dav_file_upload_cleanup);
     
     ui_set(upload->label_top_left, "");
     ui_set(upload->label_top_right, "");
--- a/application/upload.h	Wed Nov 27 17:14:57 2024 +0100
+++ b/application/upload.h	Wed Nov 27 18:45:08 2024 +0100
@@ -37,6 +37,7 @@
 #endif
 
 typedef struct DavFileUpload {
+    DavTransfer trans;
     DavBrowser *browser;
     DavSession *sn;
     UiFileList files;
--- a/application/window.c	Wed Nov 27 17:14:57 2024 +0100
+++ b/application/window.c	Wed Nov 27 18:45:08 2024 +0100
@@ -87,7 +87,6 @@
         }
 
         ui_path_textfield(obj, .fill = UI_ON, .getpathelm = dav_get_pathelm, .onactivate = action_path_selected, .varname = "path");
-
         ui_progressspinner(obj, .value = wdata->progress);
     }
 
--- a/ui/common/types.c	Wed Nov 27 17:14:57 2024 +0100
+++ b/ui/common/types.c	Wed Nov 27 18:45:08 2024 +0100
@@ -544,3 +544,36 @@
     }
     free(list.files);
 }
+
+
+typedef struct UiObserverDestructor {
+    UiList *list;
+    UiObserver *observer;
+} UiObserverDestructor;
+
+static void observer_destructor(UiObserverDestructor *destr) {
+    UiObserver *remove_obs = destr->observer;
+    UiObserver *obs = destr->list->observers;
+    UiObserver *prev = NULL;
+    while(obs) {
+        if(obs == remove_obs) {
+            if(prev) {
+                prev->next = obs->next;
+            } else {
+                destr->list->observers = obs->next;
+            }
+            break;
+        }
+        prev = obs;
+        obs = obs->next;
+    }
+    free(remove_obs);
+}
+
+void uic_list_register_observer_destructor(UiContext *ctx, UiList *list, UiObserver *observer) {
+    CxMempool *mp = ctx->mp;
+    UiObserverDestructor *destr = cxMalloc(mp->allocator, sizeof(UiObserverDestructor));
+    destr->list = list;
+    destr->observer = observer;
+    cxMempoolSetDestructor(destr, (cx_destructor_func)observer_destructor);
+}
--- a/ui/common/types.h	Wed Nov 27 17:14:57 2024 +0100
+++ b/ui/common/types.h	Wed Nov 27 18:45:08 2024 +0100
@@ -58,6 +58,8 @@
 void uic_range_unbind(UiRange *r);
 void uic_list_unbind(UiList *l);
 void uic_generic_unbind(UiGeneric *g);
+
+void uic_list_register_observer_destructor(UiContext *ctx, UiList *list, UiObserver *observer);
   
 #ifdef	__cplusplus
 }
--- a/ui/gtk/menu.c	Wed Nov 27 17:14:57 2024 +0100
+++ b/ui/gtk/menu.c	Wed Nov 27 18:45:08 2024 +0100
@@ -35,6 +35,7 @@
 #include "toolkit.h"
 #include "../common/context.h"
 #include "../common/menu.h"
+#include "../common/types.h"
 #include "../ui/properties.h"
 #include "../ui/window.h"
 #include "container.h"
@@ -252,10 +253,9 @@
     ls->callback = il->callback;
     ls->userdata = il->userdata;
     
-    ls->list->observers = ui_add_observer(
-            ls->list->observers,
-            (ui_callback)ui_update_menuitem_list,
-            ls);
+    UiObserver *observer = ui_observer_new((ui_callback)ui_update_menuitem_list, ls);
+    list->observers = ui_obsvlist_add(list->observers, observer);
+    uic_list_register_observer_destructor(obj->ctx, list, observer);
     
     ui_update_menuitem_list(NULL, ls);
 }
@@ -510,10 +510,9 @@
     ls->callback = il->callback;
     ls->userdata = il->userdata;
     
-    list->observers = ui_add_observer(
-            list->observers,
-            (ui_callback)ui_update_gmenu_item_list,
-            ls);
+    UiObserver *observer = ui_observer_new((ui_callback)ui_update_gmenu_item_list, ls);
+    list->observers = ui_obsvlist_add(list->observers, observer);
+    uic_list_register_observer_destructor(obj->ctx, list, observer);
     
     GSimpleAction *action = g_simple_action_new(item->id, g_variant_type_new("i"));
     g_action_map_add_action(obj->ctx->action_map, G_ACTION(action));

mercurial