Allow to interrupt running sync task, incl. some cleanups.

This commit is contained in:
Klaas Freitag 2012-04-30 08:56:56 +02:00
parent f96fa3dbeb
commit 9c4613e5d2
18 changed files with 211 additions and 75 deletions

View file

@ -452,23 +452,43 @@ void Application::slotInfoFolder( const QString& alias )
SyncResult folderResult = _folderMan->syncResult( alias );
QString folderMessage = tr( "Last sync was succesful." );
bool enabled = true;
Folder *f = _folderMan->folder( alias );
if( f && ! f->syncEnabled() ) {
enabled = false;
}
QString folderMessage;
SyncResult::Status syncStatus = folderResult.status();
if ( syncStatus == SyncResult::Error ) {
folderMessage = tr( "<b>Syncing Error</b><br/>" );
} else if ( syncStatus == SyncResult::SetupError ) {
folderMessage = tr( "<b>Setup Error</b><br/>" );
} else if ( syncStatus == SyncResult::Disabled ) {
folderMessage = tr( "<b>Disabled Folder</b><br/>" ).arg( folderResult.errorString() );
} else if ( syncStatus == SyncResult::Undefined ) {
folderMessage = tr( "<b>Undefined state</b><br/>" );
switch( syncStatus ) {
case SyncResult::Undefined:
folderMessage = tr( "Undefined Folder State" );
break;
case SyncResult::NotYetStarted:
folderMessage = tr( "The folder waits to start syncing." );
break;
case SyncResult::SyncRunning:
folderMessage = tr("Sync is running.");
break;
case SyncResult::Success:
folderMessage = tr("Last Sync was successful.");
break;
case SyncResult::Error:
folderMessage = tr( "Syncing Error." );
break;
case SyncResult::SetupError:
folderMessage = tr( "Setup Error." );
break;
default:
folderMessage = tr( "Undefined Error State." );
}
folderMessage = QLatin1String("<b>") + folderMessage + QLatin1String("</b><br/>");
QMessageBox infoBox( QMessageBox::Information, tr( "Folder information" ), alias, QMessageBox::Ok );
QStringList li = folderResult.errorStrings();
foreach( const QString l, li ) {
folderMessage += "<p>" + l +"</p>";
folderMessage += QString("<p>%1</p>").arg( l );
}
infoBox.setText( folderMessage );
@ -507,7 +527,22 @@ void Application::slotEnableFolder(const QString& alias, const bool enable)
qDebug() << "Application: enable folder with alias " << alias;
_folderMan->slotEnableFolder( alias, enable );
_statusDialog->slotUpdateFolderState( _folderMan->folder(alias));
// this sets the folder status to disabled but does not interrupt it.
Folder *f = _folderMan->folder( alias );
if( f && !enable ) {
// check if a sync is still running and if so, ask if we should terminate.
if( f->isBusy() ) { // its still running
QMessageBox::StandardButton b = QMessageBox::question( 0, tr("Sync Running"),
tr("The syncing operation is running.<br/>Do you want to terminate it?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes );
if( b == QMessageBox::Yes ) {
_folderMan->terminateSyncProcess( alias );
}
}
}
_statusDialog->slotUpdateFolderState( f );
}
void Application::slotConfigure()
@ -544,43 +579,44 @@ void Application::computeOverallSyncStatus()
SyncResult folderResult = syncedFolder->syncResult();
SyncResult::Status syncStatus = folderResult.status();
if( ! folderResult.localRunOnly() ) { // skip local runs, use the last message.
if ( syncStatus == SyncResult::Success ) {
folderMessage = tr( "Folder %1: Ok." ).arg( syncedFolder->alias() );
} else if ( syncStatus == SyncResult::Error ) {
if( ! folderResult.localRunOnly() && syncedFolder->syncEnabled() ) { // skip local runs, use the last message.
switch( syncStatus ) {
case SyncResult::Undefined:
if ( overallResult.status() != SyncResult::Error ) {
overallResult = SyncResult::Error;
}
folderMessage = tr( "Undefined State." );
break;
case SyncResult::NotYetStarted:
folderMessage = tr( "Waits to start syncing." );
break;
case SyncResult::SyncRunning:
folderMessage = tr( "Sync is running." );
break;
case SyncResult::Success:
folderMessage = tr( "Last Sync was successful." );
break;
case SyncResult::Error:
overallResult = SyncResult::Error;
folderMessage = tr( "Folder %1: %2" ).arg( syncedFolder->alias(), folderResult.errorString() );
} else if ( syncStatus == SyncResult::SetupError ) {
folderMessage = tr( "Syncing Error." );
break;
case SyncResult::SetupError:
if ( overallResult.status() != SyncResult::Error ) {
overallResult = SyncResult::SetupError;
}
folderMessage = tr( "Folder %1: setup error" ).arg( syncedFolder->alias() );
} else if ( syncStatus == SyncResult::Disabled ) {
if ( overallResult.status() != SyncResult::SetupError
&& overallResult.status() != SyncResult::Error ) {
overallResult = SyncResult::Disabled;
}
folderMessage = tr( "Folder %1: %2" ).arg( syncedFolder->alias(), folderResult.errorString() );
} else if ( syncStatus == SyncResult::Undefined ) {
if ( overallResult.status() == SyncResult::Success ) {
overallResult = SyncResult::Undefined;
}
folderMessage = tr( "Folder %1: undefined state" ).arg( syncedFolder->alias() );
folderMessage = tr( "Setup Error." );
break;
default:
folderMessage = tr( "Undefined Error State." );
}
}
_overallStatusStrings[syncedFolder] = folderMessage;
_overallStatusStrings[syncedFolder] = QString("Folder %1: %2").arg(syncedFolder->alias()).arg(folderMessage);
}
// create the tray blob message
QStringList allStatusStrings = _overallStatusStrings.values();
trayMessage = allStatusStrings.join("\n");
#if 0
if( _statusDialog->isVisible() ) {
_statusDialog->slotUpdateFolderState( syncedFolder );
}
#endif
QIcon statusIcon = _theme->syncStateIcon( overallResult.status(), 22 );
if( overallResult.status() == SyncResult::Success ) {

View file

@ -43,7 +43,7 @@ CSyncFolder::~CSyncFolder()
bool CSyncFolder::isBusy() const
{
return false;
return (_csync && _csync->isRunning() );
}
void CSyncFolder::startSync(const QStringList &pathList)
@ -64,6 +64,13 @@ void CSyncFolder::startSync(const QStringList &pathList)
_csync->start();
}
void CSyncFolder::slotTerminateSync()
{
if( _csync ) {
_csync->terminate();
}
}
void CSyncFolder::slotCSyncStarted()
{
qDebug() << " * csync thread started";

View file

@ -36,6 +36,10 @@ public:
virtual ~CSyncFolder();
virtual void startSync(const QStringList &pathList);
virtual bool isBusy() const;
public slots:
void slotTerminateSync();
protected slots:
void slotCSyncStarted();
void slotCSyncFinished();

View file

@ -30,6 +30,8 @@ namespace Mirall {
/* static variables to hold the credentials */
QString CSyncThread::_user;
QString CSyncThread::_passwd;
QString CSyncThread::_csyncConfigDir; // to be able to remove the lock file.
QMutex CSyncThread::_mutex;
int CSyncThread::checkPermissions( TREE_WALK_FILE* file, void *data )
@ -145,6 +147,7 @@ void CSyncThread::run()
}
// FIXME: Check if we really need this stringcopy!
wStats->sourcePath = qstrdup( _source.toLocal8Bit().constData() );
_csyncConfigDir = QString::fromLocal8Bit( csync_get_config_dir( csync ));
_mutex.unlock();
qDebug() << "## CSync Thread local only: " << _localCheckOnly;
@ -280,6 +283,11 @@ void CSyncThread::setUserPwd( const QString& user, const QString& passwd )
_mutex.unlock();
}
QString CSyncThread::csyncConfigDir()
{
return _csyncConfigDir;
}
int CSyncThread::getauth(const char *prompt,
char *buf,
size_t len,

View file

@ -64,6 +64,7 @@ public:
static void setUserPwd( const QString&, const QString& );
static int checkPermissions( TREE_WALK_FILE* file, void *data);
static QString csyncConfigDir();
signals:
void treeWalkResult(WalkStats*);
@ -81,6 +82,7 @@ private:
static QMutex _mutex;
static QString _user;
static QString _passwd;
static QString _csyncConfigDir;
QString _source;
QString _target;

View file

@ -113,8 +113,7 @@ void Folder::setSyncEnabled( bool doit )
_syncResult.clearErrors();
evaluateSync( QStringList() );
} else {
// disabled.
_syncResult.setStatus( SyncResult::Disabled );
// disable folder. Done through the _enabled-flag set above
}
}

View file

@ -130,12 +130,21 @@ public:
QString backend() const;
QIcon icon( int size ) const;
QTimer *_pollTimer;
QTimer *_pollTimer;
public slots:
void slotSyncFinished(const SyncResult &);
/**
*
*/
void slotChanged(const QStringList &pathList = QStringList() );
/**
* terminate the current sync run
*/
virtual void slotTerminateSync() = 0;
protected:
/**
* The minimum amounts of seconds to wait before

View file

@ -211,7 +211,19 @@ void FolderMan::slotEnableFolder( const QString& alias, bool enable )
}
Folder *f = _folderMap[alias];
f->setSyncEnabled(enable);
if( f ) {
f->setSyncEnabled(enable);
}
}
// this really terminates, ie. no questions, no prisoners.
// csync still remains in a stable state, regardless of that.
void FolderMan::terminateSyncProcess( const QString& alias )
{
Folder *f = _folderMap[alias];
if( f ) {
f->slotTerminateSync();
}
}
Folder *FolderMan::folder( const QString& alias )
@ -269,6 +281,7 @@ void FolderMan::slotScheduleFolderSync()
return;
}
qDebug() << "XX slotScheduleFolderSync: folderQueue size: " << _scheduleQueue.count();
if( ! _scheduleQueue.isEmpty() ) {
const QString alias = _scheduleQueue.takeFirst();
if( _folderMap.contains( alias ) ) {
@ -299,7 +312,7 @@ void FolderMan::slotFolderSyncFinished( const SyncResult& )
removeFolder( _currentSyncFolder );
_folderToDelete = false;
}
_currentSyncFolder = QString();
_currentSyncFolder.clear();
QTimer::singleShot(200, this, SLOT(slotScheduleFolderSync()));
}

View file

@ -84,6 +84,8 @@ public slots:
void slotReparseConfiguration();
void terminateSyncProcess( const QString& );
private slots:
// slot to add a folder to the syncing queue
void slotScheduleSync( const QString & );

View file

@ -177,7 +177,7 @@ QString MirallConfigFile::ownCloudUrl( const QString& connection, bool webdav )
if( webdav ) url.append( "files/webdav.php/" );
}
qDebug() << "Returning configured owncloud url: " << url;
// qDebug() << "Returning configured owncloud url: " << url;
return url;
}
@ -191,7 +191,7 @@ QString MirallConfigFile::ownCloudUser( const QString& connection ) const
settings.beginGroup( con );
QString user = settings.value( "user" ).toString();
qDebug() << "Returning configured owncloud user: " << user;
// qDebug() << "Returning configured owncloud user: " << user;
return user;
}

View file

@ -77,7 +77,7 @@ void ownCloudFolder::slotPollTimerRemoteCheck()
bool ownCloudFolder::isBusy() const
{
return false;
return ( _csync && _csync->isRunning() );
}
QString ownCloudFolder::secondPath() const
@ -85,7 +85,7 @@ QString ownCloudFolder::secondPath() const
QString re(_secondPath);
MirallConfigFile cfg;
const QString ocUrl = cfg.ownCloudUrl(QString(), true);
qDebug() << "**** " << ocUrl << " <-> " << re;
// qDebug() << "**** " << ocUrl << " <-> " << re;
if( re.startsWith( ocUrl ) ) {
re.remove( ocUrl );
}
@ -105,7 +105,7 @@ void ownCloudFolder::startSync(const QStringList &pathList)
qCritical() << "* ERROR csync is still running and new sync requested.";
return;
}
delete _csync;
delete _csync;
_errors.clear();
_csyncError = false;
@ -201,15 +201,19 @@ void ownCloudFolder::slotCSyncTerminated()
{
// do not ask csync here for reasons.
_syncResult.setStatus( SyncResult::Error );
_errors.append( tr("The CSync thread terminated unexpectedly.") );
_errors.append( tr("The CSync thread terminated.") );
_syncResult.setErrorStrings(_errors);
emit syncFinished( _syncResult );
_csyncError = true;
qDebug() << "-> CSync Terminated!";
// emit syncFinished( _syncResult );
}
void ownCloudFolder::slotCSyncFinished()
{
qDebug() << "-> CSync Finished slot with error " << _csyncError;
if (_csyncError) {
_syncResult.setStatus(SyncResult::Error);
qDebug() << " ** error Strings: " << _errors;
@ -224,5 +228,27 @@ void ownCloudFolder::slotCSyncFinished()
emit syncFinished( _syncResult );
}
void ownCloudFolder::slotTerminateSync()
{
qDebug() << "folder " << alias() << " Terminating!";
QString configDir = _csync->csyncConfigDir();
qDebug() << "csync's Config Dir: " << configDir;
if( _csync ) {
_csync->terminate();
_csync->wait();
delete _csync;
_csync = 0;
}
if( ! configDir.isEmpty() ) {
QFile file( configDir + QLatin1String("/lock"));
if( file.exists() ) {
qDebug() << "After termination, lock file exists and gets removed.";
file.remove();
}
}
}
} // ns

View file

@ -40,6 +40,7 @@ public:
public slots:
void startSync();
void slotTerminateSync();
private slots:
void slotCSyncStarted();

View file

@ -307,13 +307,15 @@ void StatusDialog::folderToModelItem( QStandardItem *item, Folder *f )
SyncResult res = f->syncResult();
SyncResult::Status status = res.status();
qDebug() << "Folder state is now " << status;
QString errors = res.errorStrings().join("<br/>");
item->setData( _theme->statusHeaderText( status ), Qt::ToolTipRole );
item->setData( _theme->syncStateIcon( status, 48 ), FolderViewDelegate::FolderStatusIcon );
if( f->syncEnabled() ) {
item->setData( _theme->syncStateIcon( status, 48 ), FolderViewDelegate::FolderStatusIcon );
} else {
item->setData( _theme->folderDisabledIcon(), FolderViewDelegate::FolderStatusIcon );
}
item->setData( _theme->statusHeaderText( status ), FolderViewDelegate::FolderStatus );
item->setData( errors, FolderViewDelegate::FolderErrorMsg );
}

View file

@ -31,7 +31,6 @@ public:
SyncRunning,
Success,
Error,
Disabled,
SetupError
};

View file

@ -47,43 +47,61 @@ QIcon Theme::syncStateIcon( SyncResult::Status status, int ) const
// FIXME: Mind the size!
QString statusIcon;
qDebug() << "Status: " << status;
if( status == SyncResult::NotYetStarted ) {
statusIcon = "task-ongoing";
} else if( status == SyncResult::SyncRunning ) {
statusIcon = "view-refresh";
} else if( status == SyncResult::Success ) {
statusIcon = "dialog-ok";
} else if( status == SyncResult::Error ) {
switch( status ) {
case SyncResult::Undefined:
statusIcon = "dialog-close";
} else if( status == SyncResult::Disabled ) {
break;
case SyncResult::NotYetStarted:
statusIcon = "task-ongoing";
break;
case SyncResult::SyncRunning:
statusIcon = "view-refresh";
break;
case SyncResult::Success:
statusIcon = "dialog-ok";
break;
case SyncResult::Error:
statusIcon = "dialog-close";
break;
case SyncResult::SetupError:
statusIcon = "dialog-cancel";
} else if( status == SyncResult::SetupError ) {
statusIcon = "dialog-cancel";
} else {
break;
default:
statusIcon = "dialog-close";
}
return QIcon::fromTheme( statusIcon, QIcon( QString( ":/mirall/resources/%1").arg(statusIcon) ) );
}
QIcon Theme::folderDisabledIcon() const
{
// Fixme: Do we really want the dialog-canel from theme here?
return QIcon::fromTheme( "dialog-cancel", QIcon( QString( ":/mirall/resources/dialog-cancel")) );
}
QString Theme::statusHeaderText( SyncResult::Status status ) const
{
QString resultStr;
if( status == SyncResult::NotYetStarted ) {
switch( status ) {
case SyncResult::Undefined:
resultStr = tr("Status undefined");
break;
case SyncResult::NotYetStarted:
resultStr = tr("Waiting to start sync");
} else if( status == SyncResult::SyncRunning ) {
break;
case SyncResult::SyncRunning:
resultStr = tr("Sync is running");
} else if( status == SyncResult::Success ) {
break;
case SyncResult::Success:
resultStr = tr("Sync Success");
} else if( status == SyncResult::Error ) {
break;
case SyncResult::Error:
resultStr = tr("Sync Error - Click info button for details.");
} else if( status == SyncResult::Disabled ) {
resultStr = tr("Sync Disabled");
} else if( status == SyncResult::SetupError ) {
break;
case SyncResult::SetupError:
resultStr = tr( "Setup Error" );
} else {
break;
default:
resultStr = tr("Status undefined");
}
return resultStr;

View file

@ -42,6 +42,7 @@ public:
*/
virtual QIcon folderIcon( const QString&, int ) const;
virtual QIcon syncStateIcon( SyncResult::Status, int ) const;
virtual QIcon folderDisabledIcon() const;
virtual QString statusHeaderText( SyncResult::Status ) const;
virtual QPixmap splashScreen() const = 0;
virtual QIcon applicationIcon() const;

View file

@ -89,6 +89,12 @@ void UnisonFolder::startSync(const QStringList &pathList)
_unison->start(program, args);
}
void UnisonFolder::slotTerminateSync()
{
if( _unison )
_unison->terminate();
}
void UnisonFolder::slotStarted()
{
qDebug() << " * Unison process started ( PID " << _unison->pid() << ")";

View file

@ -38,6 +38,9 @@ public:
virtual bool isBusy() const;
public slots:
void slotTerminateSync();
protected slots:
void slotReadyReadStandardOutput();
void slotReadyReadStandardError();