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 ); 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(); SyncResult::Status syncStatus = folderResult.status();
if ( syncStatus == SyncResult::Error ) { switch( syncStatus ) {
folderMessage = tr( "<b>Syncing Error</b><br/>" ); case SyncResult::Undefined:
} else if ( syncStatus == SyncResult::SetupError ) { folderMessage = tr( "Undefined Folder State" );
folderMessage = tr( "<b>Setup Error</b><br/>" ); break;
} else if ( syncStatus == SyncResult::Disabled ) { case SyncResult::NotYetStarted:
folderMessage = tr( "<b>Disabled Folder</b><br/>" ).arg( folderResult.errorString() ); folderMessage = tr( "The folder waits to start syncing." );
} else if ( syncStatus == SyncResult::Undefined ) { break;
folderMessage = tr( "<b>Undefined state</b><br/>" ); 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 ); QMessageBox infoBox( QMessageBox::Information, tr( "Folder information" ), alias, QMessageBox::Ok );
QStringList li = folderResult.errorStrings(); QStringList li = folderResult.errorStrings();
foreach( const QString l, li ) { foreach( const QString l, li ) {
folderMessage += "<p>" + l +"</p>"; folderMessage += QString("<p>%1</p>").arg( l );
} }
infoBox.setText( folderMessage ); infoBox.setText( folderMessage );
@ -507,7 +527,22 @@ void Application::slotEnableFolder(const QString& alias, const bool enable)
qDebug() << "Application: enable folder with alias " << alias; qDebug() << "Application: enable folder with alias " << alias;
_folderMan->slotEnableFolder( alias, enable ); _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() void Application::slotConfigure()
@ -544,43 +579,44 @@ void Application::computeOverallSyncStatus()
SyncResult folderResult = syncedFolder->syncResult(); SyncResult folderResult = syncedFolder->syncResult();
SyncResult::Status syncStatus = folderResult.status(); SyncResult::Status syncStatus = folderResult.status();
if( ! folderResult.localRunOnly() ) { // skip local runs, use the last message. if( ! folderResult.localRunOnly() && syncedFolder->syncEnabled() ) { // skip local runs, use the last message.
if ( syncStatus == SyncResult::Success ) { switch( syncStatus ) {
folderMessage = tr( "Folder %1: Ok." ).arg( syncedFolder->alias() ); case SyncResult::Undefined:
} else if ( syncStatus == SyncResult::Error ) { 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; overallResult = SyncResult::Error;
folderMessage = tr( "Folder %1: %2" ).arg( syncedFolder->alias(), folderResult.errorString() ); folderMessage = tr( "Syncing Error." );
} else if ( syncStatus == SyncResult::SetupError ) { break;
case SyncResult::SetupError:
if ( overallResult.status() != SyncResult::Error ) { if ( overallResult.status() != SyncResult::Error ) {
overallResult = SyncResult::SetupError; overallResult = SyncResult::SetupError;
} }
folderMessage = tr( "Folder %1: setup error" ).arg( syncedFolder->alias() ); folderMessage = tr( "Setup Error." );
} else if ( syncStatus == SyncResult::Disabled ) { break;
if ( overallResult.status() != SyncResult::SetupError default:
&& overallResult.status() != SyncResult::Error ) { folderMessage = tr( "Undefined Error State." );
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() );
} }
} }
_overallStatusStrings[syncedFolder] = folderMessage; _overallStatusStrings[syncedFolder] = QString("Folder %1: %2").arg(syncedFolder->alias()).arg(folderMessage);
} }
// create the tray blob message // create the tray blob message
QStringList allStatusStrings = _overallStatusStrings.values(); QStringList allStatusStrings = _overallStatusStrings.values();
trayMessage = allStatusStrings.join("\n"); trayMessage = allStatusStrings.join("\n");
#if 0
if( _statusDialog->isVisible() ) {
_statusDialog->slotUpdateFolderState( syncedFolder );
}
#endif
QIcon statusIcon = _theme->syncStateIcon( overallResult.status(), 22 ); QIcon statusIcon = _theme->syncStateIcon( overallResult.status(), 22 );
if( overallResult.status() == SyncResult::Success ) { if( overallResult.status() == SyncResult::Success ) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -130,12 +130,21 @@ public:
QString backend() const; QString backend() const;
QIcon icon( int size ) const; QIcon icon( int size ) const;
QTimer *_pollTimer; QTimer *_pollTimer;
public slots: public slots:
void slotSyncFinished(const SyncResult &); void slotSyncFinished(const SyncResult &);
/**
*
*/
void slotChanged(const QStringList &pathList = QStringList() ); void slotChanged(const QStringList &pathList = QStringList() );
/**
* terminate the current sync run
*/
virtual void slotTerminateSync() = 0;
protected: protected:
/** /**
* The minimum amounts of seconds to wait before * 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]; 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 ) Folder *FolderMan::folder( const QString& alias )
@ -269,6 +281,7 @@ void FolderMan::slotScheduleFolderSync()
return; return;
} }
qDebug() << "XX slotScheduleFolderSync: folderQueue size: " << _scheduleQueue.count();
if( ! _scheduleQueue.isEmpty() ) { if( ! _scheduleQueue.isEmpty() ) {
const QString alias = _scheduleQueue.takeFirst(); const QString alias = _scheduleQueue.takeFirst();
if( _folderMap.contains( alias ) ) { if( _folderMap.contains( alias ) ) {
@ -299,7 +312,7 @@ void FolderMan::slotFolderSyncFinished( const SyncResult& )
removeFolder( _currentSyncFolder ); removeFolder( _currentSyncFolder );
_folderToDelete = false; _folderToDelete = false;
} }
_currentSyncFolder = QString(); _currentSyncFolder.clear();
QTimer::singleShot(200, this, SLOT(slotScheduleFolderSync())); QTimer::singleShot(200, this, SLOT(slotScheduleFolderSync()));
} }

View file

@ -84,6 +84,8 @@ public slots:
void slotReparseConfiguration(); void slotReparseConfiguration();
void terminateSyncProcess( const QString& );
private slots: private slots:
// slot to add a folder to the syncing queue // slot to add a folder to the syncing queue
void slotScheduleSync( const QString & ); 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/" ); if( webdav ) url.append( "files/webdav.php/" );
} }
qDebug() << "Returning configured owncloud url: " << url; // qDebug() << "Returning configured owncloud url: " << url;
return url; return url;
} }
@ -191,7 +191,7 @@ QString MirallConfigFile::ownCloudUser( const QString& connection ) const
settings.beginGroup( con ); settings.beginGroup( con );
QString user = settings.value( "user" ).toString(); QString user = settings.value( "user" ).toString();
qDebug() << "Returning configured owncloud user: " << user; // qDebug() << "Returning configured owncloud user: " << user;
return user; return user;
} }

View file

@ -77,7 +77,7 @@ void ownCloudFolder::slotPollTimerRemoteCheck()
bool ownCloudFolder::isBusy() const bool ownCloudFolder::isBusy() const
{ {
return false; return ( _csync && _csync->isRunning() );
} }
QString ownCloudFolder::secondPath() const QString ownCloudFolder::secondPath() const
@ -85,7 +85,7 @@ QString ownCloudFolder::secondPath() const
QString re(_secondPath); QString re(_secondPath);
MirallConfigFile cfg; MirallConfigFile cfg;
const QString ocUrl = cfg.ownCloudUrl(QString(), true); const QString ocUrl = cfg.ownCloudUrl(QString(), true);
qDebug() << "**** " << ocUrl << " <-> " << re; // qDebug() << "**** " << ocUrl << " <-> " << re;
if( re.startsWith( ocUrl ) ) { if( re.startsWith( ocUrl ) ) {
re.remove( ocUrl ); re.remove( ocUrl );
} }
@ -105,7 +105,7 @@ void ownCloudFolder::startSync(const QStringList &pathList)
qCritical() << "* ERROR csync is still running and new sync requested."; qCritical() << "* ERROR csync is still running and new sync requested.";
return; return;
} }
delete _csync; delete _csync;
_errors.clear(); _errors.clear();
_csyncError = false; _csyncError = false;
@ -201,15 +201,19 @@ void ownCloudFolder::slotCSyncTerminated()
{ {
// do not ask csync here for reasons. // do not ask csync here for reasons.
_syncResult.setStatus( SyncResult::Error ); _syncResult.setStatus( SyncResult::Error );
_errors.append( tr("The CSync thread terminated unexpectedly.") ); _errors.append( tr("The CSync thread terminated.") );
_syncResult.setErrorStrings(_errors); _syncResult.setErrorStrings(_errors);
_csyncError = true;
emit syncFinished( _syncResult ); qDebug() << "-> CSync Terminated!";
// emit syncFinished( _syncResult );
} }
void ownCloudFolder::slotCSyncFinished() void ownCloudFolder::slotCSyncFinished()
{ {
qDebug() << "-> CSync Finished slot with error " << _csyncError;
if (_csyncError) { if (_csyncError) {
_syncResult.setStatus(SyncResult::Error); _syncResult.setStatus(SyncResult::Error);
qDebug() << " ** error Strings: " << _errors; qDebug() << " ** error Strings: " << _errors;
@ -224,5 +228,27 @@ void ownCloudFolder::slotCSyncFinished()
emit syncFinished( _syncResult ); 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 } // ns

View file

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

View file

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

View file

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

View file

@ -47,43 +47,61 @@ QIcon Theme::syncStateIcon( SyncResult::Status status, int ) const
// FIXME: Mind the size! // FIXME: Mind the size!
QString statusIcon; QString statusIcon;
qDebug() << "Status: " << status; switch( status ) {
case SyncResult::Undefined:
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 ) {
statusIcon = "dialog-close"; 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"; statusIcon = "dialog-cancel";
} else if( status == SyncResult::SetupError ) { break;
statusIcon = "dialog-cancel"; default:
} else {
statusIcon = "dialog-close"; statusIcon = "dialog-close";
} }
return QIcon::fromTheme( statusIcon, QIcon( QString( ":/mirall/resources/%1").arg(statusIcon) ) ); 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 Theme::statusHeaderText( SyncResult::Status status ) const
{ {
QString resultStr; 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"); resultStr = tr("Waiting to start sync");
} else if( status == SyncResult::SyncRunning ) { break;
case SyncResult::SyncRunning:
resultStr = tr("Sync is running"); resultStr = tr("Sync is running");
} else if( status == SyncResult::Success ) { break;
case SyncResult::Success:
resultStr = tr("Sync Success"); resultStr = tr("Sync Success");
} else if( status == SyncResult::Error ) { break;
case SyncResult::Error:
resultStr = tr("Sync Error - Click info button for details."); resultStr = tr("Sync Error - Click info button for details.");
} else if( status == SyncResult::Disabled ) { break;
resultStr = tr("Sync Disabled"); case SyncResult::SetupError:
} else if( status == SyncResult::SetupError ) {
resultStr = tr( "Setup Error" ); resultStr = tr( "Setup Error" );
} else { break;
default:
resultStr = tr("Status undefined"); resultStr = tr("Status undefined");
} }
return resultStr; return resultStr;

View file

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

View file

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

View file

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