File indexing completed on 2024-05-12 15:58:43
0001 /* 0002 * SPDX-FileCopyrightText: 2011 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_stroke_strategy_undo_command_based.h" 0008 0009 #include <QMutexLocker> 0010 #include "kis_image_interfaces.h" 0011 #include "kis_post_execution_undo_adapter.h" 0012 #include "commands_new/kis_saved_commands.h" 0013 0014 0015 KisStrokeStrategyUndoCommandBased::Data::~Data() 0016 { 0017 // acts as a key function 0018 } 0019 0020 KisStrokeStrategyUndoCommandBased:: 0021 KisStrokeStrategyUndoCommandBased(const KUndo2MagicString &name, 0022 bool undo, 0023 KisStrokeUndoFacade *undoFacade, 0024 KUndo2CommandSP initCommand, 0025 KUndo2CommandSP finishCommand) 0026 : KisRunnableBasedStrokeStrategy(QLatin1String("STROKE_UNDO_COMMAND_BASED"), name), 0027 m_undo(undo), 0028 m_initCommand(initCommand), 0029 m_finishCommand(finishCommand), 0030 m_undoFacade(undoFacade), 0031 m_macroId(-1), 0032 m_macroCommand(0) 0033 { 0034 enableJob(KisSimpleStrokeStrategy::JOB_INIT); 0035 enableJob(KisSimpleStrokeStrategy::JOB_FINISH); 0036 enableJob(KisSimpleStrokeStrategy::JOB_CANCEL); 0037 enableJob(KisSimpleStrokeStrategy::JOB_DOSTROKE); 0038 } 0039 0040 KisStrokeStrategyUndoCommandBased:: 0041 KisStrokeStrategyUndoCommandBased(const KisStrokeStrategyUndoCommandBased &rhs) 0042 : KisRunnableBasedStrokeStrategy(rhs), 0043 m_undo(false), 0044 m_initCommand(rhs.m_initCommand), 0045 m_finishCommand(rhs.m_finishCommand), 0046 m_undoFacade(rhs.m_undoFacade), 0047 m_macroCommand(0) 0048 { 0049 KIS_ASSERT_RECOVER_NOOP(!rhs.m_macroCommand && 0050 !rhs.m_undo && 0051 "After the stroke has been started, no copying must happen"); 0052 } 0053 0054 void KisStrokeStrategyUndoCommandBased::setUsedWhileUndoRedo(bool value) 0055 { 0056 setClearsRedoOnStart(!value); 0057 setAsynchronouslyCancellable(!value); 0058 } 0059 0060 void KisStrokeStrategyUndoCommandBased::executeCommand(KUndo2CommandSP command, bool undo) 0061 { 0062 if(!command) return; 0063 0064 if (MutatedCommandInterface *mutatedCommand = dynamic_cast<MutatedCommandInterface*>(command.data())) { 0065 mutatedCommand->setRunnableJobsInterface(this->runnableJobsInterface()); 0066 } 0067 0068 if(undo) { 0069 command->undo(); 0070 } else { 0071 command->redo(); 0072 } 0073 } 0074 0075 void KisStrokeStrategyUndoCommandBased::initStrokeCallback() 0076 { 0077 if(m_undoFacade) { 0078 m_macroCommand = m_undoFacade->postExecutionUndoAdapter()->createMacro(name()); 0079 } 0080 0081 executeCommand(m_initCommand, m_undo); 0082 notifyCommandDone(m_initCommand, 0083 KisStrokeJobData::SEQUENTIAL, 0084 KisStrokeJobData::NORMAL); 0085 } 0086 0087 void KisStrokeStrategyUndoCommandBased::finishStrokeCallback() 0088 { 0089 executeCommand(m_finishCommand, m_undo); 0090 notifyCommandDone(m_finishCommand, 0091 KisStrokeJobData::SEQUENTIAL, 0092 KisStrokeJobData::NORMAL); 0093 0094 QMutexLocker locker(&m_mutex); 0095 if(m_macroCommand) { 0096 Q_ASSERT(m_undoFacade); 0097 postProcessToplevelCommand(m_macroCommand); 0098 m_undoFacade->postExecutionUndoAdapter()->addMacro(m_macroCommand); 0099 m_macroCommand = 0; 0100 } 0101 } 0102 0103 void KisStrokeStrategyUndoCommandBased::cancelStrokeCallback() 0104 { 0105 QVector<KisStrokeJobData *> jobs; 0106 cancelStrokeCallbackImpl(jobs); 0107 addMutatedJobs(jobs); 0108 } 0109 0110 void KisStrokeStrategyUndoCommandBased::cancelStrokeCallbackImpl(QVector<KisStrokeJobData*> &mutatedJobs) 0111 { 0112 QMutexLocker locker(&m_mutex); 0113 if(m_macroCommand) { 0114 m_macroCommand->getCommandExecutionJobs(&mutatedJobs, !m_undo); 0115 0116 delete m_macroCommand; 0117 m_macroCommand = 0; 0118 } 0119 } 0120 0121 void KisStrokeStrategyUndoCommandBased::doStrokeCallback(KisStrokeJobData *data) 0122 { 0123 Data *d = dynamic_cast<Data*>(data); 0124 0125 if (d) { 0126 executeCommand(d->command, d->undo); 0127 if (d->shouldGoToHistory) { 0128 notifyCommandDone(d->command, 0129 d->sequentiality(), 0130 d->exclusivity()); 0131 } 0132 } else { 0133 KisRunnableBasedStrokeStrategy::doStrokeCallback(data); 0134 } 0135 0136 } 0137 0138 void KisStrokeStrategyUndoCommandBased::runAndSaveCommand(KUndo2CommandSP command, 0139 KisStrokeJobData::Sequentiality sequentiality, 0140 KisStrokeJobData::Exclusivity exclusivity) 0141 { 0142 if (!command) return; 0143 0144 executeCommand(command, false); 0145 notifyCommandDone(command, sequentiality, exclusivity); 0146 } 0147 0148 void KisStrokeStrategyUndoCommandBased::notifyCommandDone(KUndo2CommandSP command, 0149 KisStrokeJobData::Sequentiality sequentiality, 0150 KisStrokeJobData::Exclusivity exclusivity) 0151 { 0152 if(!command) return; 0153 0154 QMutexLocker locker(&m_mutex); 0155 if(m_macroCommand) { 0156 m_macroCommand->addCommand(command, sequentiality, exclusivity); 0157 } 0158 } 0159 0160 void KisStrokeStrategyUndoCommandBased::setCommandExtraData(KUndo2CommandExtraData *data) 0161 { 0162 if (m_undoFacade && m_macroCommand) { 0163 warnKrita << "WARNING: KisStrokeStrategyUndoCommandBased::setCommandExtraData():" 0164 << "the extra data is set while the stroke has already been started!" 0165 << "The result is undefined, continued actions may not work!"; 0166 } 0167 0168 m_commandExtraData.reset(data); 0169 } 0170 0171 void KisStrokeStrategyUndoCommandBased::setMacroId(int value) 0172 { 0173 m_macroId = value; 0174 } 0175 0176 void KisStrokeStrategyUndoCommandBased::postProcessToplevelCommand(KUndo2Command *command) 0177 { 0178 if (m_commandExtraData) { 0179 command->setExtraData(m_commandExtraData.take()); 0180 } 0181 0182 KisSavedMacroCommand *savedCommand = dynamic_cast<KisSavedMacroCommand*>(command); 0183 if (savedCommand) { 0184 savedCommand->setMacroId(m_macroId); 0185 } 0186 } 0187 0188 KisStrokeUndoFacade* KisStrokeStrategyUndoCommandBased::undoFacade() const 0189 { 0190 return m_undoFacade; 0191 }