summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Dirk Hohndel <dirk@hohndel.org>2015-09-09 13:02:39 -0700
committerGravatar Dirk Hohndel <dirk@hohndel.org>2015-09-09 13:02:39 -0700
commit2025bc1b2bd2e52f27edb67a418e1519d3d664d8 (patch)
tree68c3991f21abdbdc9801c434b8d841c217d65d43
parent2c74a8c315441b95da98e3f4b35db1b9eefb76ff (diff)
downloadsubsurface-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.c41
-rw-r--r--git-access.h1
-rw-r--r--qt-ui/mainwindow.cpp58
-rw-r--r--qt-ui/mainwindow.h8
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