From 9c4613e5d285813ec2147daa3773068c1fb12185 Mon Sep 17 00:00:00 2001 From: Klaas Freitag Date: Mon, 30 Apr 2012 08:56:56 +0200 Subject: [PATCH] Allow to interrupt running sync task, incl. some cleanups. --- src/mirall/application.cpp | 108 +++++++++++++++++++++----------- src/mirall/csyncfolder.cpp | 9 ++- src/mirall/csyncfolder.h | 4 ++ src/mirall/csyncthread.cpp | 8 +++ src/mirall/csyncthread.h | 2 + src/mirall/folder.cpp | 3 +- src/mirall/folder.h | 11 +++- src/mirall/folderman.cpp | 17 ++++- src/mirall/folderman.h | 2 + src/mirall/mirallconfigfile.cpp | 4 +- src/mirall/owncloudfolder.cpp | 38 +++++++++-- src/mirall/owncloudfolder.h | 1 + src/mirall/statusdialog.cpp | 8 ++- src/mirall/syncresult.h | 1 - src/mirall/theme.cpp | 60 +++++++++++------- src/mirall/theme.h | 1 + src/mirall/unisonfolder.cpp | 6 ++ src/mirall/unisonfolder.h | 3 + 18 files changed, 211 insertions(+), 75 deletions(-) diff --git a/src/mirall/application.cpp b/src/mirall/application.cpp index 718b5564e..1eb8340cd 100644 --- a/src/mirall/application.cpp +++ b/src/mirall/application.cpp @@ -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( "Syncing Error
" ); - } else if ( syncStatus == SyncResult::SetupError ) { - folderMessage = tr( "Setup Error
" ); - } else if ( syncStatus == SyncResult::Disabled ) { - folderMessage = tr( "Disabled Folder
" ).arg( folderResult.errorString() ); - } else if ( syncStatus == SyncResult::Undefined ) { - folderMessage = tr( "Undefined state
" ); + 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("") + folderMessage + QLatin1String("
"); QMessageBox infoBox( QMessageBox::Information, tr( "Folder information" ), alias, QMessageBox::Ok ); QStringList li = folderResult.errorStrings(); foreach( const QString l, li ) { - folderMessage += "

" + l +"

"; + folderMessage += QString("

%1

").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.
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 ) { diff --git a/src/mirall/csyncfolder.cpp b/src/mirall/csyncfolder.cpp index 54c7cbf5a..8380d9059 100644 --- a/src/mirall/csyncfolder.cpp +++ b/src/mirall/csyncfolder.cpp @@ -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"; diff --git a/src/mirall/csyncfolder.h b/src/mirall/csyncfolder.h index 006eac9ad..e601191e3 100644 --- a/src/mirall/csyncfolder.h +++ b/src/mirall/csyncfolder.h @@ -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(); diff --git a/src/mirall/csyncthread.cpp b/src/mirall/csyncthread.cpp index c8b9e1003..4e2f61392 100644 --- a/src/mirall/csyncthread.cpp +++ b/src/mirall/csyncthread.cpp @@ -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, diff --git a/src/mirall/csyncthread.h b/src/mirall/csyncthread.h index 7a19c11eb..152fe398d 100644 --- a/src/mirall/csyncthread.h +++ b/src/mirall/csyncthread.h @@ -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; diff --git a/src/mirall/folder.cpp b/src/mirall/folder.cpp index 72a0b7e6d..5d2abdcc6 100644 --- a/src/mirall/folder.cpp +++ b/src/mirall/folder.cpp @@ -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 } } diff --git a/src/mirall/folder.h b/src/mirall/folder.h index 254fde7d0..dd66c5bf7 100644 --- a/src/mirall/folder.h +++ b/src/mirall/folder.h @@ -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 diff --git a/src/mirall/folderman.cpp b/src/mirall/folderman.cpp index 02c5e8193..3fe482395 100644 --- a/src/mirall/folderman.cpp +++ b/src/mirall/folderman.cpp @@ -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())); } diff --git a/src/mirall/folderman.h b/src/mirall/folderman.h index cf229c8e2..48ec5de56 100644 --- a/src/mirall/folderman.h +++ b/src/mirall/folderman.h @@ -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 & ); diff --git a/src/mirall/mirallconfigfile.cpp b/src/mirall/mirallconfigfile.cpp index da883137c..f12d56f18 100644 --- a/src/mirall/mirallconfigfile.cpp +++ b/src/mirall/mirallconfigfile.cpp @@ -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; } diff --git a/src/mirall/owncloudfolder.cpp b/src/mirall/owncloudfolder.cpp index 353f3c4ea..2b4a145de 100644 --- a/src/mirall/owncloudfolder.cpp +++ b/src/mirall/owncloudfolder.cpp @@ -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 diff --git a/src/mirall/owncloudfolder.h b/src/mirall/owncloudfolder.h index 1acf402dd..17b0841f6 100644 --- a/src/mirall/owncloudfolder.h +++ b/src/mirall/owncloudfolder.h @@ -40,6 +40,7 @@ public: public slots: void startSync(); + void slotTerminateSync(); private slots: void slotCSyncStarted(); diff --git a/src/mirall/statusdialog.cpp b/src/mirall/statusdialog.cpp index 2ce944836..9c6d52917 100644 --- a/src/mirall/statusdialog.cpp +++ b/src/mirall/statusdialog.cpp @@ -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("
"); 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 ); } diff --git a/src/mirall/syncresult.h b/src/mirall/syncresult.h index 54789b3ef..2899a9873 100644 --- a/src/mirall/syncresult.h +++ b/src/mirall/syncresult.h @@ -31,7 +31,6 @@ public: SyncRunning, Success, Error, - Disabled, SetupError }; diff --git a/src/mirall/theme.cpp b/src/mirall/theme.cpp index 2dcd7bf23..f1d15d06c 100644 --- a/src/mirall/theme.cpp +++ b/src/mirall/theme.cpp @@ -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; diff --git a/src/mirall/theme.h b/src/mirall/theme.h index f80407daa..54261e6cf 100644 --- a/src/mirall/theme.h +++ b/src/mirall/theme.h @@ -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; diff --git a/src/mirall/unisonfolder.cpp b/src/mirall/unisonfolder.cpp index 6e142f660..2c6373b95 100644 --- a/src/mirall/unisonfolder.cpp +++ b/src/mirall/unisonfolder.cpp @@ -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() << ")"; diff --git a/src/mirall/unisonfolder.h b/src/mirall/unisonfolder.h index aaa762e81..e3620e715 100644 --- a/src/mirall/unisonfolder.h +++ b/src/mirall/unisonfolder.h @@ -38,6 +38,9 @@ public: virtual bool isBusy() const; +public slots: + void slotTerminateSync(); + protected slots: void slotReadyReadStandardOutput(); void slotReadyReadStandardError();