21 #include "history_p.h"
23 #include <kcalutils/stringify.h>
25 using namespace KCalCore;
26 using namespace Akonadi;
28 History::History( QObject *parent ) : QObject( parent ), d( new Private( this ) )
30 d->mChanger =
new IncidenceChanger(
false,
this );
31 d->mChanger->setObjectName(
"changer" );
32 d->mOperationTypeInProgress = TypeNone;
34 d->mUndoAllInProgress =
false;
42 History::Private::Private(
History *qq ) : q( qq )
48 const QString &description,
49 const uint atomicOperationId )
51 Q_ASSERT_X( item.
isValid(),
"History::recordCreation()",
52 "Item must be valid." );
54 Q_ASSERT_X( item.
hasPayload<KCalCore::Incidence::Ptr>(),
"History::recordCreation()",
55 "Item must have Incidence::Ptr payload." );
57 Entry::Ptr entry(
new CreationEntry( item, description,
this ) );
59 d->stackEntry( entry, atomicOperationId );
64 const QString &description,
65 const uint atomicOperationId )
67 Q_ASSERT_X( oldItem.
isValid(),
"History::recordModification",
"old item must be valid" );
68 Q_ASSERT_X( newItem.
isValid(),
"History::recordModification",
"newItem item must be valid" );
69 Q_ASSERT_X( oldItem.
hasPayload<KCalCore::Incidence::Ptr>(),
"History::recordModification",
70 "old item must have Incidence::Ptr payload" );
71 Q_ASSERT_X( newItem.
hasPayload<KCalCore::Incidence::Ptr>(),
"History::recordModification",
72 "newItem item must have Incidence::Ptr payload" );
74 Entry::Ptr entry(
new ModificationEntry( newItem, oldItem.
payload<KCalCore::Incidence::Ptr>(),
75 description,
this ) );
79 d->stackEntry( entry, atomicOperationId );
83 const QString &description,
84 const uint atomicOperationId )
86 Q_ASSERT_X( item.
isValid(),
"History::recordDeletion",
"Item must be valid" );
93 const QString &description,
94 const uint atomicOperationId )
96 Entry::Ptr entry(
new DeletionEntry( items, description,
this ) );
100 "History::recordDeletion()",
"Item must be valid." );
101 Q_ASSERT_X( item.
hasPayload<Incidence::Ptr>(),
102 "History::recordDeletion()",
"Item must have an Incidence::Ptr payload." );
105 d->stackEntry( entry, atomicOperationId );
110 if ( !d->mUndoStack.isEmpty() )
111 return d->mUndoStack.top()->mDescription;
118 if ( !d->mRedoStack.isEmpty() )
119 return d->mRedoStack.top()->mDescription;
126 d->undoOrRedo( TypeUndo, parent );
131 d->undoOrRedo( TypeRedo, parent );
136 if ( d->mOperationTypeInProgress != TypeNone ) {
137 kWarning() <<
"Dont call History::undoAll() while an undo/redo/undoAll is in progress";
138 }
else if ( d->mEnabled ) {
139 d->mUndoAllInProgress =
true;
140 d->mCurrentParent = parent;
143 kWarning() <<
"Don't call undo/redo when History is disabled";
150 if ( d->mOperationTypeInProgress == TypeNone ) {
151 d->mRedoStack.clear();
152 d->mUndoStack.clear();
153 d->mLastErrorString.clear();
154 d->mQueuedEntries.clear();
164 return d->mLastErrorString;
167 void History::setEnabled(
bool enabled )
169 if ( enabled != d->mEnabled ) {
170 d->mEnabled = enabled;
176 return !d->mUndoStack.isEmpty() && d->mOperationTypeInProgress == TypeNone;
181 return !d->mRedoStack.isEmpty() && d->mOperationTypeInProgress == TypeNone;
186 mEntryInProgress->updateIds( oldId, newId );
188 foreach(
const Entry::Ptr &entry, mUndoStack )
189 entry->updateIds( oldId, newId );
191 foreach(
const Entry::Ptr &entry, mRedoStack )
192 entry->updateIds( oldId, newId );
195 void History::Private::doIt( OperationType type )
197 mOperationTypeInProgress = type;
199 Q_ASSERT( !stack().isEmpty() );
200 mEntryInProgress = stack().pop();
202 connect( mEntryInProgress.data(), SIGNAL(finished(Akonadi::IncidenceChanger::ResultCode,QString)),
203 SLOT(handleFinished(Akonadi::IncidenceChanger::ResultCode,QString)),
204 Qt::UniqueConnection);
205 mEntryInProgress->doIt( type );
208 void History::Private::handleFinished( IncidenceChanger::ResultCode changerResult,
209 const QString &errorString )
211 Q_ASSERT( mOperationTypeInProgress != TypeNone );
212 Q_ASSERT( !( mUndoAllInProgress && mOperationTypeInProgress == TypeRedo ) );
214 const bool success = ( changerResult == IncidenceChanger::ResultCodeSuccess );
219 mLastErrorString.clear();
220 destinationStack().push( mEntryInProgress );
222 mLastErrorString = errorString;
223 stack().push( mEntryInProgress );
230 if ( !mQueuedEntries.isEmpty() ) {
232 foreach(
const Entry::Ptr &entry, mQueuedEntries ) {
233 mUndoStack.push( entry );
235 mQueuedEntries.clear();
238 emitDone( mOperationTypeInProgress, resultCode );
239 mOperationTypeInProgress = TypeNone;
243 void History::Private::stackEntry(
const Entry::Ptr &entry, uint atomicOperationId )
245 const bool useMultiEntry = ( atomicOperationId > 0 );
247 Entry::Ptr entryToPush;
249 if ( useMultiEntry ) {
250 Entry::Ptr topEntry = ( mOperationTypeInProgress == TypeNone ) ?
251 ( mUndoStack.isEmpty() ? Entry::Ptr() : mUndoStack.top() ) :
252 ( mQueuedEntries.isEmpty() ? Entry::Ptr() : mQueuedEntries.last() );
254 const bool topIsMultiEntry = qobject_cast<MultiEntry*>( topEntry.data() );
256 if ( topIsMultiEntry ) {
257 MultiEntry::Ptr multiEntry = topEntry.staticCast<MultiEntry>();
258 if ( multiEntry->mAtomicOperationId != atomicOperationId ) {
259 multiEntry = MultiEntry::Ptr(
new MultiEntry( atomicOperationId, entry->mDescription, q ) );
260 entryToPush = multiEntry;
262 multiEntry->addEntry( entry );
264 MultiEntry::Ptr multiEntry = MultiEntry::Ptr(
new MultiEntry( atomicOperationId,
265 entry->mDescription, q ) );
266 multiEntry->addEntry( entry );
267 entryToPush = multiEntry;
273 if ( mOperationTypeInProgress == TypeNone ) {
275 mUndoStack.push( entryToPush );
281 mQueuedEntries.append( entryToPush );
286 void History::Private::undoOrRedo( OperationType type, QWidget *parent )
289 Q_ASSERT( mOperationTypeInProgress == TypeNone );
291 if ( !stack( type ).isEmpty() ) {
293 mCurrentParent = parent;
296 kWarning() <<
"Don't call undo/redo when History is disabled";
299 kWarning() <<
"Don't call undo/redo when the stack is empty.";
303 QStack<Entry::Ptr>& History::Private::stack( OperationType type )
306 return type == TypeUndo ? mUndoStack : mRedoStack;
309 QStack<Entry::Ptr>& History::Private::stack()
311 return stack( mOperationTypeInProgress );
314 QStack<Entry::Ptr>& History::Private::destinationStack()
317 return mOperationTypeInProgress == TypeRedo ? mUndoStack : mRedoStack;
322 if ( type == TypeUndo ) {
323 emit q->undone( resultCode );
324 }
else if ( type == TypeRedo ){
325 emit q->redone( resultCode );
331 #include "history.moc"
332 #include "history_p.moc"