diff options
author | Dirk Hohndel <dirk@hohndel.org> | 2015-09-09 13:02:39 -0700 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2015-09-09 13:02:39 -0700 |
commit | 2025bc1b2bd2e52f27edb67a418e1519d3d664d8 (patch) | |
tree | 68c3991f21abdbdc9801c434b8d841c217d65d43 | |
parent | 2c74a8c315441b95da98e3f4b35db1b9eefb76ff (diff) | |
download | subsurface-2025bc1b2bd2e52f27edb67a418e1519d3d664d8.tar.gz |
Replace the spinner with a progress dialog for cloud storage access
Since the spinner caused all kinds of problems inside VMs, wasn't shown at
all for some people on Win10 and appeared to get stuck a lot and still
left people with the perception that Subsurface was hung, this patch takes
a more traditional approach and gives the user a progress dialog.
An additional benefit of this is that the user now can cancel a hung
transfer.
The slightly weird passing in of the callback allows for the separation of
UI and core logic code...
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r-- | git-access.c | 41 | ||||
-rw-r--r-- | git-access.h | 1 | ||||
-rw-r--r-- | qt-ui/mainwindow.cpp | 58 | ||||
-rw-r--r-- | qt-ui/mainwindow.h | 8 |
4 files changed, 82 insertions, 26 deletions
diff --git a/git-access.c b/git-access.c index e09deb69a..aa919f96b 100644 --- a/git-access.c +++ b/git-access.c @@ -45,6 +45,42 @@ git_branch_create(out, repo, branch_name, target, force) #endif +int (*update_progress_cb)(int) = NULL; + +void set_git_update_cb(int(*cb)(int)) +{ + update_progress_cb = cb; +} + +static int update_progress(int percent) +{ + int ret = 0; + if (update_progress_cb) + ret = (*update_progress_cb)(percent); + return ret; +} + +// the checkout_progress_cb doesn't allow canceling of the operation +static void progress_cb(const char *path, size_t completed_steps, size_t total_steps, void *payload) +{ + int percent = 0; + if (total_steps) + percent = 100 * completed_steps / total_steps; + (void)update_progress(percent); +} + +// this randomly assumes that 80% of the time is spent on the objects and 20% on the deltas +// if the user cancels the dialog this is passed back to libgit2 +static int transfer_progress_cb(const git_transfer_progress *stats, void *payload) +{ + int percent = 0; + if (stats->total_objects) + percent = 80 * stats->received_objects / stats->total_objects; + if (stats->total_deltas) + percent += 20 * stats->indexed_deltas / stats->total_deltas; + return update_progress(percent); +} + char *get_local_dir(const char *remote, const char *branch) { SHA_CTX ctx; @@ -79,6 +115,7 @@ static int check_clean(const char *path, unsigned int status, void *payload) static int reset_to_remote(git_repository *repo, git_reference *local, const git_oid *new_id) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + opts.progress_cb = &progress_cb; git_object *target; // If it's not checked out (bare or not HEAD), just update the reference */ @@ -158,6 +195,7 @@ int certificate_check_cb(git_cert *cert, int valid, const char *host, void *payl static int update_remote(git_repository *repo, git_remote *origin, git_reference *local, git_reference *remote, enum remote_transport rt) { git_push_options opts = GIT_PUSH_OPTIONS_INIT; + opts.callbacks.transfer_progress = &transfer_progress_cb; git_strarray refspec; const char *name = git_reference_name(local); @@ -334,6 +372,7 @@ static int check_remote_status(git_repository *repo, git_remote *origin, const c git_reference_list(&refspec, repo); #if USE_LIBGIT23_API git_push_options opts = GIT_PUSH_OPTIONS_INIT; + opts.callbacks.transfer_progress = &transfer_progress_cb; if (rt == RT_SSH) opts.callbacks.credentials = credential_ssh_cb; else if (rt == RT_HTTPS) @@ -386,6 +425,7 @@ int sync_with_remote(git_repository *repo, const char *remote, const char *branc } #if USE_LIBGIT23_API git_fetch_options opts = GIT_FETCH_OPTIONS_INIT; + opts.callbacks.transfer_progress = &transfer_progress_cb; if (rt == RT_SSH) opts.callbacks.credentials = credential_ssh_cb; else if (rt == RT_HTTPS) @@ -479,6 +519,7 @@ static git_repository *create_local_repo(const char *localdir, const char *remot int error; git_repository *cloned_repo = NULL; git_clone_options opts = GIT_CLONE_OPTIONS_INIT; + opts.fetch_opts.callbacks.transfer_progress = &transfer_progress_cb; #if USE_LIBGIT23_API if (rt == RT_SSH) opts.fetch_opts.callbacks.credentials = credential_ssh_cb; diff --git a/git-access.h b/git-access.h index 981c19fd1..beb764e7e 100644 --- a/git-access.h +++ b/git-access.h @@ -22,6 +22,7 @@ extern int do_git_save(git_repository *repo, const char *branch, const char *rem extern const char *saved_git_id; extern void clear_git_id(void); extern void set_git_id(const struct git_oid *); +void set_git_update_cb(int(*cb)(int)); #ifdef __cplusplus } diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp index c9f15ee12..d26ad2a3b 100644 --- a/qt-ui/mainwindow.cpp +++ b/qt-ui/mainwindow.cpp @@ -51,6 +51,16 @@ #include <qthelper.h> #include <QtConcurrentRun> +QProgressDialog *progressDialog = NULL; +bool progressDialogCanceled = false; + +extern "C" int updateProgress(int percent) +{ + if (progressDialog) + progressDialog->setValue(percent); + return progressDialogCanceled; +} + MainWindow *MainWindow::m_Instance = NULL; MainWindow::MainWindow() : QMainWindow(), @@ -58,8 +68,7 @@ MainWindow::MainWindow() : QMainWindow(), actionPreviousDive(0), helpView(0), state(VIEWALL), - survey(0), - spinner(0) + survey(0) { Q_ASSERT_X(m_Instance == NULL, "MainWindow", "MainWindow recreated!"); m_Instance = this; @@ -227,7 +236,7 @@ MainWindow::MainWindow() : QMainWindow(), #endif ui.menubar->show(); - + set_git_update_cb(&updateProgress); } MainWindow::~MainWindow() @@ -386,7 +395,7 @@ void MainWindow::on_actionCloudstorageopen_triggered() int error; - startSpinner(); + showProgressBar(); QByteArray fileNamePtr = QFile::encodeName(filename); error = parse_file(fileNamePtr.data()); if (!error) { @@ -395,7 +404,7 @@ void MainWindow::on_actionCloudstorageopen_triggered() } getNotificationWidget()->hideNotification(); process_dives(false, false); - stopSpinner(); + hideProgressBar(); refreshDisplay(); ui.actionAutoGroup->setChecked(autogroup); } @@ -411,14 +420,14 @@ void MainWindow::on_actionCloudstoragesave_triggered() if (information()->isEditing()) information()->acceptChanges(); - startSpinner(); + showProgressBar(); if (save_dives(filename.toUtf8().data())) { getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error); return; } - stopSpinner(); + hideProgressBar(); getNotificationWidget()->showNotification(get_error_string(), KMessageWidget::Error); set_filename(filename.toUtf8().data(), true); @@ -1783,23 +1792,28 @@ void MainWindow::setApplicationState(const QByteArray& state) { #undef SET_CURRENT_INDEX } -void MainWindow::startSpinner() +void MainWindow::showProgressBar() { - if (!spinner) { - spinner = new QtWaitingSpinner(Qt::WindowModal, this, true); - spinner->setRevolutionsPerSecond(1); - spinner->setColor(WHITE1); - spinner->setLineWidth(7); - spinner->setRoundness(40.0); - spinner->setMinimumTrailOpacity(0.25); - } - int shorterEdge = MIN(this->geometry().height(), this->geometry().width()); - spinner->setInnerRadius(shorterEdge / 12); - spinner->setLineLength(shorterEdge / 8); - spinner->start(); + if (progressDialog) + delete progressDialog; + + progressDialog = new QProgressDialog(tr("Contacting cloud service..."), tr("Cancel"), 0, 100, this); + progressDialog->setWindowModality(Qt::WindowModal); + progressDialog->setMinimumDuration(0); + progressDialogCanceled = false; + connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelCloudStorageOperation())); } -void MainWindow::stopSpinner() +void MainWindow::cancelCloudStorageOperation() { - spinner->stop(); + progressDialogCanceled = true; +} + +void MainWindow::hideProgressBar() +{ + if (progressDialog) { + progressDialog->setValue(100); + progressDialog->deleteLater(); + progressDialog = NULL; + } } diff --git a/qt-ui/mainwindow.h b/qt-ui/mainwindow.h index 713ab9d61..9ff2a2041 100644 --- a/qt-ui/mainwindow.h +++ b/qt-ui/mainwindow.h @@ -11,11 +11,11 @@ #include <QAction> #include <QUrl> #include <QUuid> +#include <QProgressDialog> #include "ui_mainwindow.h" #include "notificationwidget.h" #include "windowtitleupdate.h" -#include "qtwaitingspinner.h" struct DiveList; class QSortFilterProxyModel; @@ -174,6 +174,7 @@ slots: void on_actionConfigure_Dive_Computer_triggered(); void setDefaultState(); void setAutomaticTitle(); + void cancelCloudStorageOperation(); protected: void closeEvent(QCloseEvent *); @@ -193,8 +194,6 @@ slots: void planCreated(); void setEnabledToolbar(bool arg1); void setPlanNotes(); - void startSpinner(); - void stopSpinner(); private: Ui::MainWindow ui; @@ -208,6 +207,8 @@ private: bool askSaveChanges(); bool okToClose(QString message); void closeCurrentFile(); + void showProgressBar(); + void hideProgressBar(); void writeSettings(); int file_save(); int file_save_as(); @@ -249,7 +250,6 @@ private: QHash<QByteArray, PropertiesForQuadrant> stateProperties; WindowTitleUpdate *wtu; - QtWaitingSpinner *spinner; }; #endif // MAINWINDOW_H |