mirror of
https://github.com/nextcloud/desktop.git
synced 2024-10-24 05:15:40 +03:00
SyncEngine & UI: Progress notifications for update phase
For each directory (local and remote, we have UI update throtting code) a signal is emitted. It is used by the settings dialog and the tray menu.
This commit is contained in:
parent
b40b670639
commit
ce2741cebc
14 changed files with 88 additions and 26 deletions
|
@ -134,23 +134,6 @@ enum csync_ftw_type_e {
|
|||
CSYNC_FTW_TYPE_SKIP
|
||||
};
|
||||
|
||||
enum csync_notify_type_e {
|
||||
CSYNC_NOTIFY_INVALID,
|
||||
CSYNC_NOTIFY_START_SYNC_SEQUENCE,
|
||||
CSYNC_NOTIFY_START_DOWNLOAD,
|
||||
CSYNC_NOTIFY_START_UPLOAD,
|
||||
CSYNC_NOTIFY_PROGRESS,
|
||||
CSYNC_NOTIFY_FINISHED_DOWNLOAD,
|
||||
CSYNC_NOTIFY_FINISHED_UPLOAD,
|
||||
CSYNC_NOTIFY_FINISHED_SYNC_SEQUENCE,
|
||||
CSYNC_NOTIFY_START_DELETE,
|
||||
CSYNC_NOTIFY_END_DELETE,
|
||||
CSYNC_NOTIFY_ERROR,
|
||||
CSYNC_NOTIFY_START_LOCAL_UPDATE,
|
||||
CSYNC_NOTIFY_FINISHED_LOCAL_UPDATE,
|
||||
CSYNC_NOTIFY_START_REMOTE_UPDATE,
|
||||
CSYNC_NOTIFY_FINISHED_REMOTE_UPDATE
|
||||
};
|
||||
|
||||
/**
|
||||
* CSync File Traversal structure.
|
||||
|
@ -203,6 +186,9 @@ typedef void (*csync_log_callback) (int verbosity,
|
|||
const char *buffer,
|
||||
void *userdata);
|
||||
|
||||
typedef void (*csync_update_callback) (bool local,
|
||||
const char *dirUrl,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Allocate a csync context.
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "csync_private.h"
|
||||
|
||||
|
||||
/*
|
||||
* helper method to build up a user text for SSL problems, called from the
|
||||
|
@ -537,6 +539,8 @@ static struct listdir_context *fetch_resource_list(csync_owncloud_ctx_t *ctx, co
|
|||
}
|
||||
}
|
||||
|
||||
ctx->csync_ctx->callbacks.update_callback(false, curi, ctx->csync_ctx->callbacks.update_callback_userdata);
|
||||
|
||||
fetchCtx = c_malloc( sizeof( struct listdir_context ));
|
||||
if (!fetchCtx) {
|
||||
errno = ENOMEM;
|
||||
|
|
|
@ -54,6 +54,7 @@ struct listdir_context *get_listdir_context_from_recursive_cache(csync_owncloud_
|
|||
DEBUG_WEBDAV("get_listdir_context_from_recursive_cache No element %s in cache found", curi);
|
||||
return NULL;
|
||||
}
|
||||
ctx->csync_ctx->callbacks.update_callback(false, curi, ctx->csync_ctx->callbacks.update_callback_userdata);
|
||||
|
||||
/* Out of the element, create a listdir_context.. if we could be sure that it is immutable, we could ref instead.. need to investigate */
|
||||
fetchCtx = c_malloc( sizeof( struct listdir_context ));
|
||||
|
@ -141,6 +142,12 @@ static void propfind_results_recursive_callback(void *userdata,
|
|||
element->parent = NULL;
|
||||
c_rbtree_insert(ctx->propfind_recursive_cache, element);
|
||||
/* DEBUG_WEBDAV("results_recursive Added collection %s", newres->uri); */
|
||||
|
||||
// We do this here and in get_listdir_context_from_recursive_cache because
|
||||
// a recursive PROPFIND might take some time but we still want to
|
||||
// be informed. Later when get_listdir_context_from_recursive_cache is
|
||||
// called the DB queries might be the problem causing slowness, so do it again there then.
|
||||
ctx->csync_ctx->callbacks.update_callback(false, path, ctx->csync_ctx->callbacks.update_callback_userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,6 +196,7 @@ void fetch_resource_list_recursive(csync_owncloud_ctx_t *ctx, const char *uri, c
|
|||
int depth = NE_DEPTH_INFINITE;
|
||||
|
||||
DEBUG_WEBDAV("fetch_resource_list_recursive Starting recursive propfind %s %s", uri, curi);
|
||||
ctx->csync_ctx->callbacks.update_callback(false, curi, ctx->csync_ctx->callbacks.update_callback_userdata);
|
||||
|
||||
/* do a propfind request and parse the results in the results function, set as callback */
|
||||
hdl = ne_propfind_create(ctx->dav_session.ctx, curi, depth);
|
||||
|
|
|
@ -87,6 +87,8 @@ struct csync_s {
|
|||
struct {
|
||||
csync_auth_callback auth_function;
|
||||
void *userdata;
|
||||
csync_update_callback update_callback;
|
||||
void *update_callback_userdata;
|
||||
} callbacks;
|
||||
c_strlist_t *excludes;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ csync_vio_handle_t *csync_vio_opendir(CSYNC *ctx, const char *name) {
|
|||
return owncloud_opendir(ctx, name);
|
||||
break;
|
||||
case LOCAL_REPLICA:
|
||||
ctx->callbacks.update_callback(ctx->replica, name, ctx->callbacks.update_callback_userdata);
|
||||
return csync_vio_local_opendir(name);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -573,6 +573,14 @@ void AccountSettings::slotSetProgress(const QString& folder, const Progress::Inf
|
|||
QStandardItem *item = itemForFolder( folder );
|
||||
if( !item ) return;
|
||||
|
||||
// switch on extra space.
|
||||
item->setData( QVariant(true), FolderStatusDelegate::AddProgressSpace );
|
||||
|
||||
if (!progress._currentDiscoveredFolder.isEmpty()) {
|
||||
item->setData( tr("Discovering %1").arg(progress._currentDiscoveredFolder) , FolderStatusDelegate::SyncProgressItemString );
|
||||
return;
|
||||
}
|
||||
|
||||
if(!progress._lastCompletedItem.isEmpty()
|
||||
&& Progress::isWarningKind(progress._lastCompletedItem._status)) {
|
||||
int warnCount = item->data(FolderStatusDelegate::WarningCount).toInt();
|
||||
|
@ -600,8 +608,7 @@ void AccountSettings::slotSetProgress(const QString& folder, const Progress::Inf
|
|||
QString itemFileName = shortenFilename(folder, curItem._file);
|
||||
QString kindString = Progress::asActionString(curItem);
|
||||
|
||||
// switch on extra space.
|
||||
item->setData( QVariant(true), FolderStatusDelegate::AddProgressSpace );
|
||||
|
||||
|
||||
QString fileProgressString;
|
||||
if (Progress::isSizeDependent(curItem._instruction)) {
|
||||
|
|
|
@ -591,6 +591,7 @@ void Folder::startSync(const QStringList &pathList)
|
|||
//direct connection so the message box is blocking the sync.
|
||||
connect(_engine.data(), SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)),
|
||||
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)));
|
||||
connect(_engine.data(), SIGNAL(folderDiscovered(bool,QString)), this, SLOT(slotFolderDiscovered(bool,QString)));
|
||||
connect(_engine.data(), SIGNAL(transmissionProgress(Progress::Info)), this, SLOT(slotTransmissionProgress(Progress::Info)));
|
||||
connect(_engine.data(), SIGNAL(jobCompleted(SyncFileItem)), this, SLOT(slotJobCompleted(SyncFileItem)));
|
||||
|
||||
|
@ -688,6 +689,13 @@ void Folder::slotEmitFinishedDelayed()
|
|||
}
|
||||
|
||||
|
||||
void Folder::slotFolderDiscovered(bool local, QString folderName)
|
||||
{
|
||||
Progress::Info pi;
|
||||
pi._currentDiscoveredFolder = folderName;
|
||||
ProgressDispatcher::instance()->setProgressInfo(alias(), pi);
|
||||
}
|
||||
|
||||
|
||||
// the progress comes without a folder and the valid path set. Add that here
|
||||
// and hand the result over to the progress dispatcher.
|
||||
|
|
|
@ -157,6 +157,7 @@ private slots:
|
|||
void slotCsyncUnavailable();
|
||||
void slotSyncFinished();
|
||||
|
||||
void slotFolderDiscovered(bool local, QString folderName);
|
||||
void slotTransmissionProgress(const Progress::Info& pi);
|
||||
void slotJobCompleted(const SyncFileItem&);
|
||||
|
||||
|
|
|
@ -246,7 +246,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||
h += aliasMargin;
|
||||
|
||||
// Sync File Progress Bar: Show it if syncFile is not empty.
|
||||
if( !overallString.isEmpty()) {
|
||||
if( !overallString.isEmpty() || !itemString.isEmpty()) {
|
||||
int fileNameTextHeight = subFm.boundingRect(tr("File")).height();
|
||||
int barHeight = qMax(fileNameTextHeight, aliasFm.height()+4); ;
|
||||
int overallWidth = option.rect.width()-2*aliasMargin;
|
||||
|
|
|
@ -444,13 +444,16 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const Progress::Info
|
|||
{
|
||||
Q_UNUSED(folder);
|
||||
|
||||
QString totalSizeStr = Utility::octetsToString( progress._totalSize );
|
||||
if(progress._totalSize == 0 ) {
|
||||
if (!progress._currentDiscoveredFolder.isEmpty()) {
|
||||
_actionStatus->setText( tr("Discovering %1")
|
||||
.arg( progress._currentDiscoveredFolder ));
|
||||
} else if (progress._totalSize == 0 ) {
|
||||
quint64 currentFile = progress._completedFileCount + progress._currentItems.count();
|
||||
_actionStatus->setText( tr("Syncing %1 of %2 (%3 left)")
|
||||
.arg( currentFile ).arg( progress._totalFileCount )
|
||||
.arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 2, " ",true) ) );
|
||||
} else {
|
||||
QString totalSizeStr = Utility::octetsToString( progress._totalSize );
|
||||
_actionStatus->setText( tr("Syncing %1 (%2 left)")
|
||||
.arg( totalSizeStr )
|
||||
.arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 2, " ",true) ) );
|
||||
|
@ -491,7 +494,8 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const Progress::Info
|
|||
slotRebuildRecentMenus();
|
||||
}
|
||||
|
||||
if (progress._completedFileCount == progress._totalFileCount) {
|
||||
if (progress._completedFileCount == progress._totalFileCount
|
||||
&& progress._currentDiscoveredFolder.isEmpty()) {
|
||||
QTimer::singleShot(2000, this, SLOT(slotDisplayIdle()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,9 +108,11 @@ ProgressDispatcher::~ProgressDispatcher()
|
|||
|
||||
void ProgressDispatcher::setProgressInfo(const QString& folder, const Progress::Info& progress)
|
||||
{
|
||||
if( folder.isEmpty() ||
|
||||
(progress._currentItems.size() == 0
|
||||
&& progress._totalFileCount == 0) ) {
|
||||
if( folder.isEmpty())
|
||||
// The update phase now also has progress
|
||||
// (progress._currentItems.size() == 0
|
||||
// && progress._totalFileCount == 0) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
emit progressInfo( folder, progress );
|
||||
|
|
|
@ -39,6 +39,9 @@ namespace Progress
|
|||
struct Info {
|
||||
Info() : _totalFileCount(0), _totalSize(0), _completedFileCount(0), _completedSize(0) {}
|
||||
|
||||
// Used during local and remote update phase
|
||||
QString _currentDiscoveredFolder;
|
||||
|
||||
quint64 _totalFileCount;
|
||||
quint64 _totalSize;
|
||||
quint64 _completedFileCount;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include <QUrl>
|
||||
#include <QSslCertificate>
|
||||
#include <QProcess>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
|
@ -452,6 +453,24 @@ void SyncEngine::handleSyncError(CSYNC *ctx, const char *state) {
|
|||
finalize();
|
||||
}
|
||||
|
||||
void update_job_update_callback (bool local,
|
||||
const char *dirUrl,
|
||||
void *userdata)
|
||||
{
|
||||
// Don't wanna overload the UI
|
||||
static QElapsedTimer throttleTimer;
|
||||
if (throttleTimer.elapsed() < 200) {
|
||||
return;
|
||||
}
|
||||
throttleTimer.restart();
|
||||
|
||||
UpdateJob *updateJob = static_cast<Mirall::UpdateJob*>(userdata);
|
||||
if (updateJob) {
|
||||
QString path = QString::fromUtf8(dirUrl).section('/', -1);
|
||||
emit updateJob->folderDiscovered(local, path);
|
||||
}
|
||||
}
|
||||
|
||||
void SyncEngine::startSync()
|
||||
{
|
||||
Q_ASSERT(!_syncRunning);
|
||||
|
@ -534,11 +553,16 @@ void SyncEngine::startSync()
|
|||
UpdateJob *job = new UpdateJob(_csync_ctx);
|
||||
job->moveToThread(&_thread);
|
||||
connect(job, SIGNAL(finished(int)), this, SLOT(slotUpdateFinished(int)));
|
||||
connect(job, SIGNAL(folderDiscovered(bool,QString)),
|
||||
this, SIGNAL(folderDiscovered(bool,QString)));
|
||||
QMetaObject::invokeMethod(job, "start", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void SyncEngine::slotUpdateFinished(int updateResult)
|
||||
{
|
||||
// To clean the progress info
|
||||
emit folderDiscovered(false, QString());
|
||||
|
||||
if (updateResult < 0 ) {
|
||||
handleSyncError(_csync_ctx, "csync_update");
|
||||
return;
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
|
||||
#include <csync.h>
|
||||
|
||||
// when do we go away with this private/public separation?
|
||||
#include <csync_private.h>
|
||||
|
||||
#include "mirall/syncfileitem.h"
|
||||
#include "mirall/progressdispatcher.h"
|
||||
#include "mirall/utility.h"
|
||||
|
@ -62,6 +65,9 @@ signals:
|
|||
void csyncError( const QString& );
|
||||
void csyncUnavailable();
|
||||
|
||||
// During update, before reconcile
|
||||
void folderDiscovered(bool local, QString folderUrl);
|
||||
|
||||
// before actual syncing (after update+reconcile) for each item
|
||||
void syncItemDiscovered(const SyncFileItem&);
|
||||
// after the above signals. with the items that actually need propagating
|
||||
|
@ -141,6 +147,9 @@ private:
|
|||
QHash<QString, QByteArray> _remotePerms;
|
||||
};
|
||||
|
||||
void update_job_update_callback (bool local,
|
||||
const char *dirname,
|
||||
void *userdata);
|
||||
|
||||
class UpdateJob : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -152,6 +161,8 @@ class UpdateJob : public QObject {
|
|||
csync_set_log_callback(_log_callback);
|
||||
csync_set_log_level(_log_level);
|
||||
csync_set_log_userdata(_log_userdata);
|
||||
_csync_ctx->callbacks.update_callback = update_job_update_callback;
|
||||
_csync_ctx->callbacks.update_callback_userdata = this;
|
||||
emit finished(csync_update(_csync_ctx));
|
||||
deleteLater();
|
||||
}
|
||||
|
@ -165,6 +176,7 @@ public:
|
|||
_log_userdata = csync_get_log_userdata();
|
||||
}
|
||||
signals:
|
||||
void folderDiscovered(bool local, QString folderUrl);
|
||||
void finished(int result);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue