00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "transactionsequence.h"
00021 #include "transactionjobs.h"
00022
00023 #include "job_p.h"
00024
00025 #include <QtCore/QSet>
00026
00027 using namespace Akonadi;
00028
00029 class Akonadi::TransactionSequencePrivate : public JobPrivate
00030 {
00031 public:
00032 TransactionSequencePrivate( TransactionSequence *parent )
00033 : JobPrivate( parent ),
00034 mState( Idle ),
00035 mAutoCommit( true )
00036 {
00037 }
00038
00039 enum TransactionState
00040 {
00041 Idle,
00042 Running,
00043 WaitingForSubjobs,
00044 RollingBack,
00045 Committing
00046 };
00047
00048 Q_DECLARE_PUBLIC( TransactionSequence )
00049
00050 TransactionState mState;
00051 QSet<KJob*> mIgnoredErrorJobs;
00052 bool mAutoCommit;
00053
00054 void commitResult( KJob *job )
00055 {
00056 Q_Q( TransactionSequence );
00057
00058 if ( job->error() ) {
00059 q->setError( job->error() );
00060 q->setErrorText( job->errorText() );
00061 }
00062 q->emitResult();
00063 }
00064
00065 void rollbackResult( KJob *job )
00066 {
00067 Q_Q( TransactionSequence );
00068
00069 Q_UNUSED( job );
00070 q->emitResult();
00071 }
00072 };
00073
00074 TransactionSequence::TransactionSequence( QObject * parent )
00075 : Job( new TransactionSequencePrivate( this ), parent )
00076 {
00077 }
00078
00079 TransactionSequence::~TransactionSequence()
00080 {
00081 }
00082
00083 bool TransactionSequence::addSubjob(KJob * job)
00084 {
00085 Q_D( TransactionSequence );
00086
00087 if ( d->mState == TransactionSequencePrivate::Idle ) {
00088 d->mState = TransactionSequencePrivate::Running;
00089 new TransactionBeginJob( this );
00090 }
00091 return Job::addSubjob( job );
00092 }
00093
00094 void TransactionSequence::slotResult(KJob * job)
00095 {
00096 Q_D( TransactionSequence );
00097
00098 if ( !job->error() || d->mIgnoredErrorJobs.contains( job ) ) {
00099
00100
00101
00102 if ( !job->error() )
00103 Job::slotResult( job );
00104 else
00105 Job::removeSubjob( job );
00106
00107 if ( subjobs().isEmpty() && d->mState == TransactionSequencePrivate::WaitingForSubjobs ) {
00108 d->mState = TransactionSequencePrivate::Committing;
00109 TransactionCommitJob *job = new TransactionCommitJob( this );
00110 connect( job, SIGNAL( result( KJob* ) ), SLOT( commitResult( KJob* ) ) );
00111 }
00112 } else {
00113 setError( job->error() );
00114 setErrorText( job->errorText() );
00115 removeSubjob( job );
00116 clearSubjobs();
00117 if ( d->mState == TransactionSequencePrivate::Running || d->mState == TransactionSequencePrivate::WaitingForSubjobs ) {
00118 d->mState = TransactionSequencePrivate::RollingBack;
00119 TransactionRollbackJob *job = new TransactionRollbackJob( this );
00120 connect( job, SIGNAL( result( KJob* ) ), SLOT( rollbackResult( KJob* ) ) );
00121 }
00122 }
00123 }
00124
00125 void TransactionSequence::commit()
00126 {
00127 Q_D( TransactionSequence );
00128
00129 if ( d->mState == TransactionSequencePrivate::Running ) {
00130 d->mState = TransactionSequencePrivate::WaitingForSubjobs;
00131 } else {
00132
00133
00134 if ( d->mState == TransactionSequencePrivate::Idle )
00135 emitResult();
00136 return;
00137 }
00138
00139 if ( subjobs().isEmpty() ) {
00140 if ( !error() ) {
00141 d->mState = TransactionSequencePrivate::Committing;
00142 TransactionCommitJob *job = new TransactionCommitJob( this );
00143 connect( job, SIGNAL( result( KJob* ) ), SLOT( commitResult( KJob* ) ) );
00144 } else {
00145 d->mState = TransactionSequencePrivate::RollingBack;
00146 TransactionRollbackJob *job = new TransactionRollbackJob( this );
00147 connect( job, SIGNAL( result( KJob* ) ), SLOT( rollbackResult( KJob* ) ) );
00148 }
00149 }
00150 }
00151
00152 void TransactionSequence::setIgnoreJobFailure( KJob *job )
00153 {
00154 Q_D( TransactionSequence );
00155
00156
00157 Q_ASSERT( subjobs().contains( job ) );
00158
00159 d->mIgnoredErrorJobs.insert( job );
00160 }
00161
00162 void TransactionSequence::doStart()
00163 {
00164 Q_D( TransactionSequence );
00165
00166 if ( d->mAutoCommit ) {
00167 if ( d->mState == TransactionSequencePrivate::Idle )
00168 emitResult();
00169 else
00170 commit();
00171 }
00172 }
00173
00174 void TransactionSequence::setAutomaticCommittingEnabled(bool enable)
00175 {
00176 Q_D( TransactionSequence );
00177 d->mAutoCommit = enable;
00178 }
00179
00180 void TransactionSequence::rollback()
00181 {
00182 Q_D( TransactionSequence );
00183
00184 setError( UserCanceled );
00185
00186 if ( d->mState == TransactionSequencePrivate::Idle ) {
00187 emitResult();
00188 return;
00189 }
00190
00191
00192
00193 d->mState = TransactionSequencePrivate::RollingBack;
00194 TransactionRollbackJob *job = new TransactionRollbackJob( this );
00195 connect( job, SIGNAL( result( KJob* ) ), SLOT( rollbackResult( KJob* ) ) );
00196 }
00197
00198
00199 #include "transactionsequence.moc"