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 ( !hasSubjobs() && 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
00117
00118 foreach ( KJob* job, subjobs() ) {
00119 disconnect( job, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*)) );
00120 job->kill( EmitResult );
00121 }
00122 clearSubjobs();
00123
00124 if ( d->mState == TransactionSequencePrivate::Running || d->mState == TransactionSequencePrivate::WaitingForSubjobs ) {
00125 d->mState = TransactionSequencePrivate::RollingBack;
00126 TransactionRollbackJob *job = new TransactionRollbackJob( this );
00127 connect( job, SIGNAL( result( KJob* ) ), SLOT( rollbackResult( KJob* ) ) );
00128 }
00129 }
00130 }
00131
00132 void TransactionSequence::commit()
00133 {
00134 Q_D( TransactionSequence );
00135
00136 if ( d->mState == TransactionSequencePrivate::Running ) {
00137 d->mState = TransactionSequencePrivate::WaitingForSubjobs;
00138 } else {
00139
00140
00141 if ( d->mState == TransactionSequencePrivate::Idle )
00142 emitResult();
00143 return;
00144 }
00145
00146 if ( subjobs().isEmpty() ) {
00147 if ( !error() ) {
00148 d->mState = TransactionSequencePrivate::Committing;
00149 TransactionCommitJob *job = new TransactionCommitJob( this );
00150 connect( job, SIGNAL( result( KJob* ) ), SLOT( commitResult( KJob* ) ) );
00151 } else {
00152 d->mState = TransactionSequencePrivate::RollingBack;
00153 TransactionRollbackJob *job = new TransactionRollbackJob( this );
00154 connect( job, SIGNAL( result( KJob* ) ), SLOT( rollbackResult( KJob* ) ) );
00155 }
00156 }
00157 }
00158
00159 void TransactionSequence::setIgnoreJobFailure( KJob *job )
00160 {
00161 Q_D( TransactionSequence );
00162
00163
00164 Q_ASSERT( subjobs().contains( job ) );
00165
00166 d->mIgnoredErrorJobs.insert( job );
00167 }
00168
00169 void TransactionSequence::doStart()
00170 {
00171 Q_D( TransactionSequence );
00172
00173 if ( d->mAutoCommit ) {
00174 if ( d->mState == TransactionSequencePrivate::Idle )
00175 emitResult();
00176 else
00177 commit();
00178 }
00179 }
00180
00181 void TransactionSequence::setAutomaticCommittingEnabled(bool enable)
00182 {
00183 Q_D( TransactionSequence );
00184 d->mAutoCommit = enable;
00185 }
00186
00187 void TransactionSequence::rollback()
00188 {
00189 Q_D( TransactionSequence );
00190
00191 setError( UserCanceled );
00192
00193 if ( d->mState == TransactionSequencePrivate::Idle ) {
00194 emitResult();
00195 return;
00196 }
00197
00198
00199
00200 d->mState = TransactionSequencePrivate::RollingBack;
00201 TransactionRollbackJob *job = new TransactionRollbackJob( this );
00202 connect( job, SIGNAL( result( KJob* ) ), SLOT( rollbackResult( KJob* ) ) );
00203 }
00204
00205
00206 #include "transactionsequence.moc"