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:
Markus Goetz 2014-08-15 15:00:10 +02:00
parent b40b670639
commit ce2741cebc
14 changed files with 88 additions and 26 deletions

View file

@ -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.

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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:

View file

@ -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)) {

View file

@ -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.

View file

@ -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&);

View file

@ -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;

View file

@ -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()));
}
}

View file

@ -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 );

View file

@ -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;

View file

@ -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;

View file

@ -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);
};