application/application.c

Thu, 28 Nov 2024 18:03:12 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 28 Nov 2024 18:03:12 +0100
changeset 97
5a3d27b8e6b0
parent 96
493959648de6
permissions
-rw-r--r--

implement UI for editing properties, relates to #497

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2024 Olaf Wintermann. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "application.h"

#include <string.h>
#include <stdbool.h>

#include <libidav/webdav.h>

#include "window.h"
#include "config.h"
#include "davcontroller.h"
#include "settings.h"
#include "appsettings.h"

static DavContext* davctx;

static DavApp *app;

void application_init(void) {
    davctx = dav_context_new();
    dav_context_set_mtsafe(davctx, true);

    application_create_menu();
}

DavApp* get_application(void) {
    return app;
}

void application_startup(UiEvent* event, void* data) {
    if (load_config(davctx)) {
        // TODO: error
        exit(-1);
    }

    appsettings_init();
    window_init();

    // create document for global settings (repolist, ...)
    app = application_create_app_document();
    UiContext *global = ui_global_context();
    ui_attach_document(global, app);

    // create new window
    UiObject *win = window_create();
    // create new browser document and attach it to the main window
    DavBrowser *doc = davbrowser_create(win);
    ui_attach_document(win->ctx, doc);

    ui_show(win);
}

static void* davrepo_getname(void *elm, int unused) {
    DavCfgRepository *repo = elm;
    return repo->name.value.ptr;
}

void application_create_menu(void) {
    // menu
    ui_menu("File") {
        ui_menuitem(.label = "New Window", .onclick = action_window_new);
        ui_menuseparator();
        ui_menuitem(.label = "New Folder", .onclick = action_mkcol, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
        ui_menuitem(.label = "New File", .onclick = action_newfile, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
        ui_menuitem(.label = "Delete", .onclick = action_delete, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
        ui_menuseparator();
        ui_menuitem(.label = "Upload File", .onclick = action_upload_file, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
        ui_menuitem(.label = "Upload Folder", .onclick = action_upload_dir, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
        ui_menuitem(.label = "Download", .onclick = action_download, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION, APP_STATE_BROWSER_SELECTION));
        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_menuitem(.label = "Close", .onclick = action_window_close);
    }
    
    ui_menu("Edit") {
        ui_menuitem(.label = "Preferences", .onclick = action_open_settings);
    }
    
    ui_menu("Go") {
        ui_menuitem(.label = "Parent", .onclick = action_go_parent, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
        ui_menuitem(.label = "Back", .onclick = action_go_back, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
        ui_menuitem(.label = "Forward", .onclick = action_go_forward, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
        ui_menuseparator();
        ui_menu("Repositories") {
            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);
    ui_toolbar_item("NewWindow", .icon = UI_ICON_NEW_WINDOW, .onclick = action_window_new);
    ui_toolbar_item("Refresh", .icon = UI_ICON_REFRESH, .onclick = action_refresh, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
    ui_toolbar_menu("Repo", .label = "Repository") {
        ui_menu_itemlist(.varname = "repolist", .getvalue = davrepo_getname, .onselect = action_repo_selected);
    }
    ui_toolbar_item("NewFolder", .icon = UI_ICON_NEW_FOLDER, .onclick = action_mkcol, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
    ui_toolbar_item("NewFile", .icon = UI_ICON_ADD, .onclick = action_newfile, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
    ui_toolbar_item("Upload", .label = "Upload", .icon = UI_ICON_UPLOAD, .onclick = action_upload_file, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
    ui_toolbar_item("Download", .icon = UI_ICON_SAVE_LOCAL, .onclick = action_download, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION, APP_STATE_BROWSER_SELECTION));
    ui_toolbar_item("Remove", .icon = UI_ICON_DELETE, .onclick = action_delete, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION, APP_STATE_BROWSER_SELECTION));
    ui_toolbar_toggleitem("LocalBrowser", .icon = UI_ICON_DOCK_LEFT, .label = "Local Browser");
    ui_toolbar_toggleitem("PreviewPane", .icon = UI_ICON_DOCK_RIGHT);

    ui_toolbar_appmenu() {
        ui_menuitem("New Window", .onclick = action_window_new);
        ui_menuseparator();
        ui_menuitem("Download", .onclick = action_download, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION, APP_STATE_BROWSER_SELECTION));
        ui_menuitem("Upload Files", .onclick = action_upload_file, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
        ui_menuitem("Upload Directory", .onclick = action_upload_dir, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
        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);
    }

    //ui_toolbar_add_default("Home", UI_TOOLBAR_LEFT);
    //ui_toolbar_add_default("NewWindow", UI_TOOLBAR_LEFT);
    //ui_toolbar_add_default("Refresh", UI_TOOLBAR_LEFT);
    ui_toolbar_add_default("Repo", UI_TOOLBAR_LEFT);

    ui_toolbar_add_default("NewFolder", UI_TOOLBAR_CENTER);
    ui_toolbar_add_default("NewFile", UI_TOOLBAR_CENTER);
    ui_toolbar_add_default("Remove", UI_TOOLBAR_CENTER);
    ui_toolbar_add_default("Download", UI_TOOLBAR_CENTER);
    ui_toolbar_add_default("Upload", UI_TOOLBAR_CENTER);

    //ui_toolbar_add_default("LocalBrowser", UI_TOOLBAR_RIGHT);
    //ui_toolbar_add_default("PreviewPane", UI_TOOLBAR_RIGHT);
}



DavApp* application_create_app_document(void) {
    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);

    return doc;
}

void application_update_repolist(DavApp *app) {
    DavConfig *config = get_config();

    ui_list_clear(app->repos);

    for (DavCfgRepository *repo = config->repositories; repo; repo = repo->next) {
        ui_list_append(app->repos, repo);
    }
    
    ui_notify(app->repos->observers, NULL);
}


DavContext* application_dav_context(void) {
    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();
    // create new browser document and attach it to the main window
    DavBrowser *doc = davbrowser_create(win);
    ui_attach_document(win->ctx, doc);

    ui_show(win);
}

void action_window_close(UiEvent *event, void *data) {
    ui_close(event->obj);
}

void action_refresh(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    if (browser->current) {
        davbrowser_query_path(event->obj, browser, browser->current->path);
    }
}

void action_repo_selected(UiEvent *event, void *data) {
    DavCfgRepository *repo = event->eventdata;
    DavBrowser *browser = event->document;
    davbrowser_connect2repo(event->obj, browser, repo, "");
}

static void file_selected(UiEvent *event, void *data) {
    UiFileList *files = event->eventdata;
    if (files && files->nfiles > 0) {
        // files will be freed by the filedialog handler, therefore we need a copy
        UiFileList uploadList = ui_filelist_copy(*files); // uploadList will be freed by davbrowser_upload_files
        davbrowser_upload_files(event->obj, event->document, uploadList);
    }
    
}



static void download_location_selected(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    DavResource *reslist = data;
    UiFileList *flist = event->eventdata;

    if (flist && flist->nfiles > 0) {
        davbrowser_download(event->obj, browser, reslist, flist->files[0]);
    } else {
        dav_session_destroy(reslist->session);
    }
}

void action_download(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    UiListSelection sel = ui_list_getselection(browser->resources);
    if (sel.count > 0) {;
        const char *initialFileName = NULL;
        if (sel.count == 1) {
            DavResource *res = ui_list_get(browser->resources, sel.rows[0]);
            if (res && !res->iscollection) {
                initialFileName = res->name;
            }
        }

        // create a copy of the current session and all selected resources
        DavSession *sn = dav_session_clone(browser->sn);
        DavResource *first = NULL;
        DavResource *last = NULL;
        for (int i = 0; i < sel.count; i++) {
            // get selected resource
            DavResource *res = ui_list_get(browser->resources, sel.rows[i]);
            // copy resource
            DavResource *res_copy = dav_resource_new(sn, res->path);
            res_copy->iscollection = res->iscollection;
            res_copy->contentlength = res->contentlength;
            res_copy->lastmodified = res->lastmodified;
            res_copy->creationdate = res->creationdate;

            // link resources
            if (!first) {
                first = res_copy;
            }
            if (last) {
                res_copy->prev = last;
                last->next = res_copy;
            }
            last = res_copy;
        }

        if (initialFileName) {
            ui_savefiledialog(event->obj, initialFileName, download_location_selected, first);
        } else {
            ui_openfiledialog(event->obj, UI_FILEDIALOG_SELECT_FOLDER, download_location_selected, first);
        }
        
        ui_listselection_free(sel);
    }
}

void action_upload_file(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    if(!browser->sn) {
        return;
    }
    ui_openfiledialog(event->obj, UI_FILEDIALOG_SELECT_MULTI, file_selected, NULL);
}

void action_upload_dir(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    if(!browser->sn) {
        return;
    }
    ui_openfiledialog(event->obj, UI_FILEDIALOG_SELECT_FOLDER|UI_FILEDIALOG_SELECT_MULTI, file_selected, NULL);
}

void action_delete(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    UiListSelection sel = ui_list_getselection(browser->resources);
    if (sel.count > 0) {
        davbrowser_delete(event->obj, browser, sel);
    }
    ui_listselection_free(sel);
}

void action_selectall(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    int nres = ui_list_count(browser->resources);
    for(int i=0;i<nres;i++) {
        ui_list_setselection(browser->resources, i);
    }
}

void action_rename(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    UiListSelection sel = ui_list_getselection(browser->resources);
    if (sel.count == 1) {
        davbrowser_rename(event->obj, browser, sel);
    } else if(sel.count > 1) {
        fprintf(stderr, "Renaming multiple resources is not implemented yet\n");
    }
}

static void newfiledialog_result(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    char *path = event->eventdata;
    if (event->intval == 1) {
        davbrowser_newfile(event->obj, browser, path);
    }
}

void action_newfile(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    if(!browser->sn) {
        return;
    }
    
    ui_dialog(event->obj,
            .content = "New File",
            .input =  TRUE,
            .button1_label = "Create File",
            .button2_label = "Cancel",
            .result = newfiledialog_result);
}


static void newfolderdialog_result(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    char *path = event->eventdata;
    if (event->intval == 1) {
        davbrowser_mkcol(event->obj, browser, path);
    }
}

void action_mkcol(UiEvent *event, void *data) {
    DavBrowser *browser = event->document;
    if(!browser->sn) {
        return;
    }
    
    
    ui_dialog(event->obj,
            .content = "New Folder",
            .input =  TRUE,
            .button1_label = "Create Folder",
            .button2_label = "Cancel",
            .result = newfolderdialog_result);
}

void action_open_settings(UiEvent *event, void *data) {
    settings_window_open();
}

void action_open_properties(UiEvent *event, void *data) {
    char *type = data;
    DavBrowser *browser = event->document;
    
    UiListSelection sel = ui_list_getselection(browser->resources);
    for(int i=0;i<sel.count;i++) {
        DavResource *res = ui_list_get(browser->resources, sel.rows[i]);
        if(res) {
            davbrowser_open_resource(event->obj, browser, res, type);
        }
    }
    ui_listselection_free(sel);
}

void action_transfer_selected(UiEvent *event, void *data) {
    DavApp *app = get_application();
    DavTransfer *trans = ui_list_get(app->transfers, event->intval);
    if(trans) {
        ui_show(trans->window);
    }
}

mercurial