27#include "preferencemanager.h"
28#include "layermanager.h"
29#include "soundmanager.h"
30#include "undoredomanager.h"
31#include "selectionmanager.h"
33#include "undoredocommand.h"
34#include "legacybackupelement.h"
36#include "layerbitmap.h"
37#include "layervector.h"
38#include "layersound.h"
41#include "bitmapimage.h"
42#include "vectorimage.h"
45UndoRedoManager::UndoRedoManager(
Editor* editor) :
BaseManager(editor,
"UndoRedoManager")
47 qDebug() <<
"UndoRedoManager: created";
50UndoRedoManager::~UndoRedoManager()
52 if (!mNewBackupSystemEnabled)
57 qDebug() <<
"UndoRedoManager: destroyed";
60bool UndoRedoManager::init()
62 qDebug() <<
"UndoRedoManager: init";
64 mUndoStack.
setUndoLimit(editor()->preference()->getInt(SETTING::UNDO_REDO_MAX_STEPS));
65 mNewBackupSystemEnabled = editor()->preference()->isOn(SETTING::NEW_UNDO_REDO_SYSTEM_ON);
70void UndoRedoManager::onSettingChanged(SETTING setting)
72 if (setting == SETTING::UNDO_REDO_MAX_STEPS) {
75 qDebug() <<
"updated undo stack limit";
76 mUndoStack.
setUndoLimit(editor()->preference()->getInt(SETTING::UNDO_REDO_MAX_STEPS));
88 if (mNewBackupSystemEnabled) {
90 }
else if (!mLegacyBackupList.
isEmpty() && mLegacyBackupIndex < mLegacyBackupList.
count()) {
91 mLegacyBackupAtSave = mLegacyBackupList[mLegacyBackupIndex];
98 if (!mSaveStates.
contains(saveStateId)) {
103 if (!saveState) {
return; }
105 if (!mNewBackupSystemEnabled) {
106 clearState(saveState);
110 switch (saveState->recordType)
112 case UndoRedoRecordType::KEYFRAME_MODIFY: {
113 replaceKeyFrame(*saveState, description);
116 case UndoRedoRecordType::KEYFRAME_REMOVE: {
117 removeKeyFrame(*saveState, description);
120 case UndoRedoRecordType::KEYFRAME_ADD: {
121 addKeyFrame(*saveState, description);
124 case UndoRedoRecordType::KEYFRAME_MOVE: {
125 moveKeyFrames(*saveState, description);
129 QString reason(
"Unhandled case for: ");
130 reason.
append(description);
131 Q_ASSERT_X(
false,
"UndoRedoManager::record", qPrintable(reason));
137 clearState(saveState);
148void UndoRedoManager::clearSaveStates()
161 if (mNewBackupSystemEnabled) {
164 if (mLegacyBackupIndex >= 0) {
165 return mLegacyBackupAtSave != mLegacyBackupList[mLegacyBackupIndex];
173 mUndoStack.
push(command);
175 emit didUpdateUndoStack();
184 pushCommand(element);
193 pushCommand(element);
196void UndoRedoManager::replaceKeyFrame(
const UndoSaveState& undoState,
const QString& description)
198 if (undoState.layerType == Layer::BITMAP) {
199 replaceBitmap(undoState, description);
200 }
else if (undoState.layerType == Layer::VECTOR) {
201 replaceVector(undoState, description);
215 pushCommand(element);
220 if (undoState.keyframe ==
nullptr || undoState.layerType != Layer::BITMAP) {
return; }
228 selectionState.translation,
229 selectionState.rotationAngle,
230 selectionState.scaleX,
231 selectionState.scaleY,
232 selectionState.anchor,
237 pushCommand(element);
242 if (undoState.keyframe ==
nullptr || undoState.layerType != Layer::VECTOR) {
return; }
250 selectionState.translation,
251 selectionState.rotationAngle,
252 selectionState.scaleX,
253 selectionState.scaleY,
254 selectionState.anchor,
258 pushCommand(element);
263 int saveStateId = mSaveStateId;
265 state->recordType = recordType;
266 initCommonKeyFrameState(state);
268 mSaveStates[saveStateId] = state;
276 if (!mSaveStates.contains(saveStateId)) {
return; }
277 mSaveStates[saveStateId]->userState = userState;
280void UndoRedoManager::initCommonKeyFrameState(
UndoSaveState* undoSaveState)
const
282 const Layer* layer = editor()->layers()->currentLayer();
283 undoSaveState->layerType = layer->type();
284 undoSaveState->layerId = layer->id();
285 undoSaveState->currentFrameIndex = editor()->currentFrame();
287 if (layer->type() == Layer::BITMAP || layer->type() == Layer::VECTOR) {
288 auto selectMan = editor()->select();
290 selectMan->mySelectionRect(),
291 selectMan->myRotation(),
292 selectMan->myScaleX(),
293 selectMan->myScaleY(),
294 selectMan->myTranslation(),
295 selectMan->currentTransformAnchor());
298 const int frameIndex = editor()->currentFrame();
299 auto keyframe = layer->getKeyFrameWhichCovers(frameIndex);
300 if (keyframe ==
nullptr)
302 keyframe = layer->getLastKeyFrameAtPosition(frameIndex);
305 if (keyframe !=
nullptr) {
306 undoSaveState->keyframe = std::unique_ptr<KeyFrame>(keyframe->clone());
313 if (mNewBackupSystemEnabled) {
322 if (mNewBackupSystemEnabled) {
333 if (mNewBackupSystemEnabled) {
342 if (mNewBackupSystemEnabled) {
350void UndoRedoManager::updateUndoAction(
QAction* undoAction)
352 if (mNewBackupSystemEnabled) {
356 if (mLegacyBackupIndex < 0)
358 undoAction->
setText(
tr(
"Undo",
"Menu item text"));
360 qDebug() << undoAction->
text();
365 .arg(mLegacyBackupIndex + 1)
366 .arg(mLegacyBackupList.
at(mLegacyBackupIndex)->undoText));
368 .arg(mLegacyBackupIndex + 1)
369 .arg(mLegacyBackupList.
at(mLegacyBackupIndex)->undoText));
371 qDebug() << undoAction->
text();
376void UndoRedoManager::updateRedoAction(
QAction* redoAction)
378 if (mNewBackupSystemEnabled) {
382 if (mLegacyBackupIndex + 2 < mLegacyBackupList.
size())
385 .arg(mLegacyBackupIndex + 2)
386 .arg(mLegacyBackupList.
at(mLegacyBackupIndex + 1)->undoText));
391 redoAction->
setText(
tr(
"Redo",
"Menu item text"));
399 if (mNewBackupSystemEnabled) {
402 mLegacyBackupIndex = -1;
403 while (!mLegacyBackupList.
isEmpty())
405 delete mLegacyBackupList.
takeLast();
407 mLegacyLastModifiedLayer = -1;
408 mLegacyLastModifiedFrame = -1;
414void UndoRedoManager::legacyBackup(
const QString& undoText)
417 if (mNewBackupSystemEnabled) {
422 int currentFrame = editor()->currentFrame();
423 if (mLegacyLastModifiedLayer > -1 && mLegacyLastModifiedFrame > 0)
425 if (editor()->layers()->currentLayer()->type() == Layer::SOUND)
427 frame = editor()->layers()->currentLayer()->getKeyFrameWhichCovers(mLegacyLastModifiedFrame);
428 if (frame !=
nullptr)
430 legacyBackup(mLegacyLastModifiedLayer, frame->pos(), undoText);
435 legacyBackup(mLegacyLastModifiedLayer, mLegacyLastModifiedFrame, undoText);
438 if (mLegacyLastModifiedLayer != editor()->layers()->currentLayerIndex() || mLegacyLastModifiedFrame != currentFrame)
440 if (editor()->layers()->currentLayer()->type() == Layer::SOUND)
442 frame = editor()->layers()->currentLayer()->getKeyFrameWhichCovers(currentFrame);
444 if (frame !=
nullptr)
446 legacyBackup(editor()->layers()->currentLayerIndex(), frame->pos(), undoText);
451 legacyBackup(editor()->layers()->currentLayerIndex(), currentFrame, undoText);
456bool UndoRedoManager::legacyBackup(
int backupLayer,
int backupFrame,
const QString& undoText)
458 if (mNewBackupSystemEnabled) {
462 while (mLegacyBackupList.
size() - 1 > mLegacyBackupIndex && !mLegacyBackupList.
empty())
464 delete mLegacyBackupList.
takeLast();
466 while (mLegacyBackupList.
size() >= editor()->preference()->getInt(SETTING::UNDO_REDO_MAX_STEPS))
469 mLegacyBackupIndex--;
472 Layer* layer = editor()->layers()->getLayer(backupLayer);
473 int currentFrame = editor()->currentFrame();
474 if (layer !=
nullptr)
476 if (layer->type() == Layer::BITMAP)
479 if (currentFrame == 1)
481 int previous = layer->getPreviousKeyFramePosition(backupFrame);
482 bitmapImage =
static_cast<BitmapImage*
>(layer->getKeyFrameAt(previous));
484 if (bitmapImage !=
nullptr)
487 element->layerId = layer->id();
488 element->layer = backupLayer;
489 element->frame = bitmapImage->pos();
490 element->undoText = undoText;
491 element->somethingSelected = editor()->select()->somethingSelected();
492 element->mySelection = editor()->select()->mySelectionRect();
493 element->rotationAngle = editor()->select()->myRotation();
494 element->scaleX = editor()->select()->myScaleX();
495 element->scaleY = editor()->select()->myScaleY();
496 element->translation = editor()->select()->myTranslation();
497 element->selectionAnchor = editor()->select()->currentTransformAnchor();
499 mLegacyBackupList.
append(element);
500 mLegacyBackupIndex++;
507 else if (layer->type() == Layer::VECTOR)
510 if (vectorImage !=
nullptr)
513 element->layerId = layer->id();
514 element->layer = backupLayer;
515 element->frame = vectorImage->pos();
516 element->undoText = undoText;
517 element->somethingSelected = editor()->select()->somethingSelected();
518 element->mySelection = editor()->select()->mySelectionRect();
519 element->rotationAngle = editor()->select()->myRotation();
520 element->scaleX = editor()->select()->myScaleX();
521 element->scaleY = editor()->select()->myScaleY();
522 element->translation = editor()->select()->myTranslation();
523 element->selectionAnchor = editor()->select()->currentTransformAnchor();
524 mLegacyBackupList.
append(element);
525 mLegacyBackupIndex++;
532 else if (layer->type() == Layer::SOUND)
534 int previous = layer->getPreviousKeyFramePosition(backupFrame);
535 KeyFrame* key = layer->getLastKeyFrameAtPosition(backupFrame);
540 KeyFrame* previousKey = layer->getKeyFrameAt(previous);
543 if (key !=
nullptr) {
548 element->layerId = layer->id();
549 element->layer = backupLayer;
550 element->frame = backupFrame;
551 element->undoText = undoText;
552 element->fileName = clip->fileName();
553 element->originalName = clip->soundClipName();
554 mLegacyBackupList.
append(element);
555 mLegacyBackupIndex++;
565 emit didUpdateUndoStack();
572 if (mNewBackupSystemEnabled) {
576 for (
int i = 0; i < mLegacyBackupList.
size(); i++)
582 switch (backupElement->type())
584 case LegacyBackupElement::BITMAP_MODIF:
585 bitmapElement = qobject_cast<BackupLegacyBitmapElement*>(backupElement);
586 Q_ASSERT(bitmapElement);
587 if (bitmapElement->layer > layerIndex)
589 bitmapElement->layer--;
592 else if (bitmapElement->layer != layerIndex)
597 case LegacyBackupElement::VECTOR_MODIF:
598 vectorElement = qobject_cast<BackupLegacyVectorElement*>(backupElement);
599 Q_ASSERT(vectorElement);
600 if (vectorElement->layer > layerIndex)
602 vectorElement->layer--;
605 else if (vectorElement->layer != layerIndex)
610 case LegacyBackupElement::SOUND_MODIF:
611 soundElement = qobject_cast<BackupLegacySoundElement*>(backupElement);
612 Q_ASSERT(soundElement);
613 if (soundElement->layer > layerIndex)
615 soundElement->layer--;
618 else if (soundElement->layer != layerIndex)
626 if (i <= mLegacyBackupIndex)
628 mLegacyBackupIndex--;
630 delete mLegacyBackupList.
takeAt(i);
635void UndoRedoManager::restoreLegacyKey()
637 if (mNewBackupSystemEnabled) {
643 Layer* layer =
nullptr;
646 if (lastBackupElement->type() == LegacyBackupElement::BITMAP_MODIF)
649 layerIndex = lastBackupBitmapElement->layer;
650 frame = lastBackupBitmapElement->frame;
651 layer = object()->findLayerById(lastBackupBitmapElement->layerId);
653 dynamic_cast<LayerBitmap*
>(layer)->getBitmapImageAtFrame(frame)->paste(&lastBackupBitmapElement->bitmapImage);
654 editor()->setModified(layerIndex, frame);
656 if (lastBackupElement->type() == LegacyBackupElement::VECTOR_MODIF)
659 layerIndex = lastBackupVectorElement->layer;
660 frame = lastBackupVectorElement->frame;
661 layer = object()->findLayerById(layerIndex);
663 dynamic_cast<LayerVector*
>(layer)->getVectorImageAtFrame(frame)->paste(lastBackupVectorElement->vectorImage);
664 editor()->setModified(layerIndex, frame);
666 if (lastBackupElement->type() == LegacyBackupElement::SOUND_MODIF)
670 layerIndex = lastBackupSoundElement->layer;
671 frame = lastBackupSoundElement->frame;
673 strSoundFile = lastBackupSoundElement->fileName;
674 if (strSoundFile.
isEmpty())
return;
679 Status st = editor()->sound()->loadSound(clip, lastBackupSoundElement->fileName);
680 clip->setSoundClipName(lastBackupSoundElement->originalName);
683 editor()->removeKey();
684 emit editor()->layers()->currentLayerChanged(editor()->layers()->currentLayerIndex());
690void UndoRedoManager::legacyUndo()
692 if (!mLegacyBackupList.
empty() && mLegacyBackupIndex > -1)
694 if (mLegacyBackupIndex == mLegacyBackupList.
size() - 1)
697 if (lastBackupElement->type() == LegacyBackupElement::BITMAP_MODIF)
700 if (legacyBackup(lastBackupBitmapElement->layer, lastBackupBitmapElement->frame,
"NoOp"))
702 mLegacyBackupIndex--;
705 if (lastBackupElement->type() == LegacyBackupElement::VECTOR_MODIF)
708 if (legacyBackup(lastBackupVectorElement->layer, lastBackupVectorElement->frame,
"NoOp"))
710 mLegacyBackupIndex--;
713 if (lastBackupElement->type() == LegacyBackupElement::SOUND_MODIF)
716 if (legacyBackup(lastBackupSoundElement->layer, lastBackupSoundElement->frame,
"NoOp"))
718 mLegacyBackupIndex--;
723 qDebug() <<
"Undo" << mLegacyBackupIndex;
724 mLegacyBackupList[mLegacyBackupIndex]->restore(editor());
725 mLegacyBackupIndex--;
727 emit didUpdateUndoStack();
731void UndoRedoManager::legacyRedo()
733 if (!mLegacyBackupList.
empty() && mLegacyBackupIndex < mLegacyBackupList.
size() - 2)
735 mLegacyBackupIndex++;
737 mLegacyBackupList[mLegacyBackupIndex + 1]->restore(editor());
738 emit didUpdateUndoStack();
742void UndoRedoManager::rememberLastModifiedFrame(
int layerNumber,
int frameNumber)
744 if (mNewBackupSystemEnabled) {
747 mLegacyLastModifiedLayer = layerNumber;
748 mLegacyLastModifiedFrame = frameNumber;
KeyFrame * addKeyFrame(int layerNumber, int frameIndex)
Attempts to create a new keyframe at the given position and layer.
bool hasUnsavedChanges() const
Checks whether there are unsaved changes.
void sanitizeLegacyBackupElementsAfterLayerDeletion(int layerIndex)
Restores integrity of the backup elements after a layer has been deleted.
void addUserState(SAVESTATE_ID SaveStateId, const UserSaveState &userState)
Adds userState to the saveState found at SaveStateId If no record is found matching the id,...
void record(SAVESTATE_ID SaveStateId, const QString &description)
Records the given save state.
SAVESTATE_ID createState(UndoRedoRecordType recordType)
Prepares and returns an save state with common data.
void clearStack()
Clears the undo stack.
void setIcon(const QIcon &icon)
void setIconText(const QString &text)
void setText(const QString &text)
void triggered(bool checked)
void append(const T &value)
const T & at(int i) const const
int count(const T &value) const const
bool isEmpty() const const
bool contains(const Key &key) const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
QString tr(const char *sourceText, const char *disambiguation, int n)
QString & append(QChar ch)
bool isEmpty() const const
QAction * createRedoAction(QObject *parent, const QString &prefix) const const
QAction * createUndoAction(QObject *parent, const QString &prefix) const const
bool isClean() const const
void push(QUndoCommand *cmd)
void setUndoLimit(int limit)
This is the main undo/redo state structure which is meant to populate whatever states that needs to b...
Use this struct to store user related data that will later be added to the backup This struct is mean...