/// This method undos the given controller change. This method does NOT undo document changes /// @param controller the controller to undo the change form /// @return true if a change has been undone. bool TextUndoStack::undoControllerChange(TextEditorController* controller) { Q_ASSERT(controller); int changeIdx = controllerIndexMap_.value(controller)-1; // -1, because the index is directly AFTER the item Change* changeToUndo = findUndoChange( controller ); if( changeToUndo && changeToUndo->controllerContext() ) { Q_ASSERT( changeToUndo->controllerContext() == controller ); changeToUndo->revert( documentRef_ ); controllerIndexMap_[controller] = findUndoIndex( changeIdx, controller )+1; emit undoExecuted( changeToUndo ); return true; } return false; }
/// undo's the given controller change bool TextUndoStack::redoControllerChange(TextEditorController *controller) { Q_ASSERT(controller); int changeIdx = findRedoIndex( currentIndex(controller), controller); Change* changeToRedo = findRedoChange( controller ); if( changeToRedo && changeToRedo->controllerContext() ) { Q_ASSERT( changeToRedo->controllerContext() == controller ); changeToRedo->execute( documentRef_ ); // move the pointer to the next controllerIndexMap_[controller] = changeIdx+1; emit redoExecuted( changeToRedo ); } return false; }
/// Performs an document-change undo. void TextUndoStack::undoDocumentChange() { // first make sure ALL controller-changes are back to the document change-level QMap<TextEditorController*, int>::iterator itr; for( itr = controllerIndexMap_.begin(); itr != controllerIndexMap_.end(); ++itr) { TextEditorController* controller = itr.key(); while( undoControllerChange(controller) ) {}; // undo all controller operations } // next perform an undo of the document operations Change* change = findUndoChange(); if( change ) { Q_ASSERT( change->controllerContext() == 0 ); change->revert( documentRef_ ); // next move the pointers to first 'related' change for( itr = controllerIndexMap_.begin(); itr != controllerIndexMap_.end(); ++itr) { TextEditorController* controller = itr.key(); controllerIndexMap_[controller] = findUndoIndex( changeIndex_-1, controller ) + 1; // +1 because the pointer points AFTER the found index } // and finally move the document pointer setChangeIndex( findUndoIndex( changeIndex_-1 ) + 1 ); // +1 because the pointer points AFTER the found index emit undoExecuted( change); } }
/// performs the redo operation for the given controller /// @param controller the controller to execute the redo for /// @param controllerOnly undo controller undo's only? void TextUndoStack::redo(TextEditorController* controller, bool controllerOnly ) { Q_ASSERT(!redoRunning_); redoRunning_ = true; resetAllLastCoalesceIds(); Change* changeToRedo = findRedoChange( controller ); if( changeToRedo && changeToRedo->controllerContext() ) { Q_ASSERT(changeToRedo->controllerContext() == controller ); redoControllerChange( controller ); } else if( !controllerOnly ){ redoDocumentChange(); } dumpStackInternal(); redoRunning_ = false; }
/// This method finds the index of the given stackitem from the given index /// @param index the previous index /// @param controller the controller context /// @return the previous index -1, if there's no previous index int TextUndoStack::findUndoIndex( int index, TextEditorController* controller) { if( index > 0 ) { for( --index; index >= 0; --index ) { Change* change = at(index); TextEditorController* context = change->controllerContext(); if( context == 0 || context == controller ) { return index; } } } return -1; }
/// performs an undo operation /// @param controller this method is called void TextUndoStack::undo(TextEditorController* controller, bool controllerOnly ) { Q_ASSERT(!undoRunning_); undoRunning_ = true; resetAllLastCoalesceIds(); Change* changeToUndo = this->findUndoChange( controller ); // only for the current controller if( changeToUndo && changeToUndo->controllerContext() ) { Q_ASSERT(changeToUndo->controllerContext() == controller ); undoControllerChange( controller ); // else we need to undo ALL other controller changes } else if( !controllerOnly ) { undoDocumentChange( ); } dumpStackInternal(); undoRunning_ = false; }
/// This method finds the next redo-item /// @param index the index to search it from /// @param controller the controller context /// @return the next change index. Or changeList_.size() if there's no next change int TextUndoStack::findRedoIndex(int index, TextEditorController* controller) { if( index < changeList_.size() ) { int size = changeList_.size(); for( ; index < size; ++index ) { Change* change = at(index); TextEditorController* context = change->controllerContext(); if( context == 0 || context == controller ) { return index; } } } return changeList_.size(); }