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