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 if (layer->keyExists(frameIndex))
301 undoSaveState->keyframe = std::unique_ptr<KeyFrame>(layer->getLastKeyFrameAtPosition(frameIndex)->clone());
303 else if (layer->getKeyFrameWhichCovers(frameIndex) !=
nullptr)
305 undoSaveState->keyframe = std::unique_ptr<KeyFrame>(layer->getKeyFrameWhichCovers(frameIndex)->clone());
312 if (mNewBackupSystemEnabled) {
321 if (mNewBackupSystemEnabled) {
332 if (mNewBackupSystemEnabled) {
341 if (mNewBackupSystemEnabled) {
349void UndoRedoManager::updateUndoAction(
QAction* undoAction)
351 if (mNewBackupSystemEnabled) {
355 if (mLegacyBackupIndex < 0)
357 undoAction->
setText(
tr(
"Undo",
"Menu item text"));
359 qDebug() << undoAction->
text();
364 .arg(mLegacyBackupIndex + 1)
365 .arg(mLegacyBackupList.
at(mLegacyBackupIndex)->undoText));
367 .arg(mLegacyBackupIndex + 1)
368 .arg(mLegacyBackupList.
at(mLegacyBackupIndex)->undoText));
370 qDebug() << undoAction->
text();
375void UndoRedoManager::updateRedoAction(
QAction* redoAction)
377 if (mNewBackupSystemEnabled) {
381 if (mLegacyBackupIndex + 2 < mLegacyBackupList.
size())
384 .arg(mLegacyBackupIndex + 2)
385 .arg(mLegacyBackupList.
at(mLegacyBackupIndex + 1)->undoText));
390 redoAction->
setText(
tr(
"Redo",
"Menu item text"));
398 if (mNewBackupSystemEnabled) {
401 mLegacyBackupIndex = -1;
402 while (!mLegacyBackupList.
isEmpty())
404 delete mLegacyBackupList.
takeLast();
406 mLegacyLastModifiedLayer = -1;
407 mLegacyLastModifiedFrame = -1;
413void UndoRedoManager::legacyBackup(
const QString& undoText)
416 if (mNewBackupSystemEnabled) {
421 int currentFrame = editor()->currentFrame();
422 if (mLegacyLastModifiedLayer > -1 && mLegacyLastModifiedFrame > 0)
424 if (editor()->layers()->currentLayer()->type() == Layer::SOUND)
426 frame = editor()->layers()->currentLayer()->getKeyFrameWhichCovers(mLegacyLastModifiedFrame);
427 if (frame !=
nullptr)
429 legacyBackup(mLegacyLastModifiedLayer, frame->pos(), undoText);
434 legacyBackup(mLegacyLastModifiedLayer, mLegacyLastModifiedFrame, undoText);
437 if (mLegacyLastModifiedLayer != editor()->layers()->currentLayerIndex() || mLegacyLastModifiedFrame != currentFrame)
439 if (editor()->layers()->currentLayer()->type() == Layer::SOUND)
441 frame = editor()->layers()->currentLayer()->getKeyFrameWhichCovers(currentFrame);
443 if (frame !=
nullptr)
445 legacyBackup(editor()->layers()->currentLayerIndex(), frame->pos(), undoText);
450 legacyBackup(editor()->layers()->currentLayerIndex(), currentFrame, undoText);
455bool UndoRedoManager::legacyBackup(
int backupLayer,
int backupFrame,
const QString& undoText)
457 if (mNewBackupSystemEnabled) {
461 while (mLegacyBackupList.
size() - 1 > mLegacyBackupIndex && !mLegacyBackupList.
empty())
463 delete mLegacyBackupList.
takeLast();
465 while (mLegacyBackupList.
size() >= editor()->preference()->getInt(SETTING::UNDO_REDO_MAX_STEPS))
468 mLegacyBackupIndex--;
471 Layer* layer = editor()->layers()->getLayer(backupLayer);
472 int currentFrame = editor()->currentFrame();
473 if (layer !=
nullptr)
475 if (layer->type() == Layer::BITMAP)
478 if (currentFrame == 1)
480 int previous = layer->getPreviousKeyFramePosition(backupFrame);
481 bitmapImage =
static_cast<BitmapImage*
>(layer->getKeyFrameAt(previous));
483 if (bitmapImage !=
nullptr)
486 element->layerId = layer->id();
487 element->layer = backupLayer;
488 element->frame = bitmapImage->pos();
489 element->undoText = undoText;
490 element->somethingSelected = editor()->select()->somethingSelected();
491 element->mySelection = editor()->select()->mySelectionRect();
492 element->rotationAngle = editor()->select()->myRotation();
493 element->scaleX = editor()->select()->myScaleX();
494 element->scaleY = editor()->select()->myScaleY();
495 element->translation = editor()->select()->myTranslation();
496 element->selectionAnchor = editor()->select()->currentTransformAnchor();
498 mLegacyBackupList.
append(element);
499 mLegacyBackupIndex++;
506 else if (layer->type() == Layer::VECTOR)
509 if (vectorImage !=
nullptr)
512 element->layerId = layer->id();
513 element->layer = backupLayer;
514 element->frame = vectorImage->pos();
515 element->undoText = undoText;
516 element->somethingSelected = editor()->select()->somethingSelected();
517 element->mySelection = editor()->select()->mySelectionRect();
518 element->rotationAngle = editor()->select()->myRotation();
519 element->scaleX = editor()->select()->myScaleX();
520 element->scaleY = editor()->select()->myScaleY();
521 element->translation = editor()->select()->myTranslation();
522 element->selectionAnchor = editor()->select()->currentTransformAnchor();
523 mLegacyBackupList.
append(element);
524 mLegacyBackupIndex++;
531 else if (layer->type() == Layer::SOUND)
533 int previous = layer->getPreviousKeyFramePosition(backupFrame);
534 KeyFrame* key = layer->getLastKeyFrameAtPosition(backupFrame);
539 KeyFrame* previousKey = layer->getKeyFrameAt(previous);
542 if (key !=
nullptr) {
547 element->layerId = layer->id();
548 element->layer = backupLayer;
549 element->frame = backupFrame;
550 element->undoText = undoText;
551 element->fileName = clip->fileName();
552 element->originalName = clip->soundClipName();
553 mLegacyBackupList.
append(element);
554 mLegacyBackupIndex++;
564 emit didUpdateUndoStack();
571 if (mNewBackupSystemEnabled) {
575 for (
int i = 0; i < mLegacyBackupList.
size(); i++)
581 switch (backupElement->type())
583 case LegacyBackupElement::BITMAP_MODIF:
584 bitmapElement = qobject_cast<BackupLegacyBitmapElement*>(backupElement);
585 Q_ASSERT(bitmapElement);
586 if (bitmapElement->layer > layerIndex)
588 bitmapElement->layer--;
591 else if (bitmapElement->layer != layerIndex)
596 case LegacyBackupElement::VECTOR_MODIF:
597 vectorElement = qobject_cast<BackupLegacyVectorElement*>(backupElement);
598 Q_ASSERT(vectorElement);
599 if (vectorElement->layer > layerIndex)
601 vectorElement->layer--;
604 else if (vectorElement->layer != layerIndex)
609 case LegacyBackupElement::SOUND_MODIF:
610 soundElement = qobject_cast<BackupLegacySoundElement*>(backupElement);
611 Q_ASSERT(soundElement);
612 if (soundElement->layer > layerIndex)
614 soundElement->layer--;
617 else if (soundElement->layer != layerIndex)
625 if (i <= mLegacyBackupIndex)
627 mLegacyBackupIndex--;
629 delete mLegacyBackupList.
takeAt(i);
634void UndoRedoManager::restoreLegacyKey()
636 if (mNewBackupSystemEnabled) {
642 Layer* layer =
nullptr;
645 if (lastBackupElement->type() == LegacyBackupElement::BITMAP_MODIF)
648 layerIndex = lastBackupBitmapElement->layer;
649 frame = lastBackupBitmapElement->frame;
650 layer = object()->findLayerById(lastBackupBitmapElement->layerId);
652 dynamic_cast<LayerBitmap*
>(layer)->getBitmapImageAtFrame(frame)->paste(&lastBackupBitmapElement->bitmapImage);
653 editor()->setModified(layerIndex, frame);
655 if (lastBackupElement->type() == LegacyBackupElement::VECTOR_MODIF)
658 layerIndex = lastBackupVectorElement->layer;
659 frame = lastBackupVectorElement->frame;
660 layer = object()->findLayerById(layerIndex);
662 dynamic_cast<LayerVector*
>(layer)->getVectorImageAtFrame(frame)->paste(lastBackupVectorElement->vectorImage);
663 editor()->setModified(layerIndex, frame);
665 if (lastBackupElement->type() == LegacyBackupElement::SOUND_MODIF)
669 layerIndex = lastBackupSoundElement->layer;
670 frame = lastBackupSoundElement->frame;
672 strSoundFile = lastBackupSoundElement->fileName;
673 if (strSoundFile.
isEmpty())
return;
678 Status st = editor()->sound()->loadSound(clip, lastBackupSoundElement->fileName);
679 clip->setSoundClipName(lastBackupSoundElement->originalName);
682 editor()->removeKey();
683 emit editor()->layers()->currentLayerChanged(editor()->layers()->currentLayerIndex());
689void UndoRedoManager::legacyUndo()
691 if (!mLegacyBackupList.
empty() && mLegacyBackupIndex > -1)
693 if (mLegacyBackupIndex == mLegacyBackupList.
size() - 1)
696 if (lastBackupElement->type() == LegacyBackupElement::BITMAP_MODIF)
699 if (legacyBackup(lastBackupBitmapElement->layer, lastBackupBitmapElement->frame,
"NoOp"))
701 mLegacyBackupIndex--;
704 if (lastBackupElement->type() == LegacyBackupElement::VECTOR_MODIF)
707 if (legacyBackup(lastBackupVectorElement->layer, lastBackupVectorElement->frame,
"NoOp"))
709 mLegacyBackupIndex--;
712 if (lastBackupElement->type() == LegacyBackupElement::SOUND_MODIF)
715 if (legacyBackup(lastBackupSoundElement->layer, lastBackupSoundElement->frame,
"NoOp"))
717 mLegacyBackupIndex--;
722 qDebug() <<
"Undo" << mLegacyBackupIndex;
723 mLegacyBackupList[mLegacyBackupIndex]->restore(editor());
724 mLegacyBackupIndex--;
726 emit didUpdateUndoStack();
730void UndoRedoManager::legacyRedo()
732 if (!mLegacyBackupList.
empty() && mLegacyBackupIndex < mLegacyBackupList.
size() - 2)
734 mLegacyBackupIndex++;
736 mLegacyBackupList[mLegacyBackupIndex + 1]->restore(editor());
737 emit didUpdateUndoStack();
741void UndoRedoManager::rememberLastModifiedFrame(
int layerNumber,
int frameNumber)
743 if (mNewBackupSystemEnabled) {
746 mLegacyLastModifiedLayer = layerNumber;
747 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...