diff --git a/libs/ui/KisChangeCloneLayersCommand.cpp b/libs/ui/KisChangeCloneLayersCommand.cpp index bbec880008..2d8c29a75d 100644 --- a/libs/ui/KisChangeCloneLayersCommand.cpp +++ b/libs/ui/KisChangeCloneLayersCommand.cpp @@ -1,58 +1,70 @@ /* * Copyright (c) 2019 Tusooa Zhu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisChangeCloneLayersCommand.h" #include struct KisChangeCloneLayersCommand::Private { QList cloneLayers; QList originalSource; KisLayerSP newSource; }; KisChangeCloneLayersCommand::KisChangeCloneLayersCommand(QList cloneLayers, KisLayerSP newSource, KUndo2Command *parent) : KUndo2Command(kundo2_i18n("Change Clone Layers"), parent) , d(new Private()) { KIS_SAFE_ASSERT_RECOVER_RETURN(!cloneLayers.isEmpty()); d->cloneLayers = cloneLayers; Q_FOREACH (KisCloneLayerSP layer, d->cloneLayers) { d->originalSource << layer->copyFrom(); } d->newSource = newSource; } void KisChangeCloneLayersCommand::redo() { Q_FOREACH (KisCloneLayerSP layer, d->cloneLayers) { layer->setCopyFrom(d->newSource); layer->setDirty(); } } void KisChangeCloneLayersCommand::undo() { KIS_SAFE_ASSERT_RECOVER_RETURN(d->cloneLayers.size() == d->originalSource.size()); for (int i = 0; i < d->cloneLayers.size(); ++i) { KisCloneLayerSP layer = d->cloneLayers.at(i); layer->setCopyFrom(d->originalSource.at(i)); layer->setDirty(); } } + +bool KisChangeCloneLayersCommand::mergeWith(const KUndo2Command *command) +{ + const KisChangeCloneLayersCommand *other = dynamic_cast(command); + + if (other && d->cloneLayers == other->d->cloneLayers) { + d->newSource = other->d->newSource; + return true; + } + + return false; +} diff --git a/libs/ui/KisChangeCloneLayersCommand.h b/libs/ui/KisChangeCloneLayersCommand.h index 465a84d81a..3e0308b95b 100644 --- a/libs/ui/KisChangeCloneLayersCommand.h +++ b/libs/ui/KisChangeCloneLayersCommand.h @@ -1,39 +1,40 @@ /* * Copyright (c) 2019 Tusooa Zhu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_CHANGE_CLONE_LAYERS_COMMAND_H_ #define KIS_CHANGE_CLONE_LAYERS_COMMAND_H_ #include #include "kis_types.h" class KisChangeCloneLayersCommand : public KUndo2Command { public: KisChangeCloneLayersCommand(QList cloneLayers, KisLayerSP newSource, KUndo2Command *parent = 0); void undo() override; void redo() override; + bool mergeWith(const KUndo2Command *) override; private: struct Private; QScopedPointer d; }; #endif // KIS_CHANGE_CLONE_LAYERS_COMMAND_H_ diff --git a/libs/ui/dialogs/KisDlgChangeCloneSource.cpp b/libs/ui/dialogs/KisDlgChangeCloneSource.cpp index c878b08d34..12acf01bcd 100644 --- a/libs/ui/dialogs/KisDlgChangeCloneSource.cpp +++ b/libs/ui/dialogs/KisDlgChangeCloneSource.cpp @@ -1,234 +1,193 @@ /* * Copyright (c) 2019 Tusooa Zhu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisDlgChangeCloneSource.h" #include #include #include #include #include +#include #include "KisViewManager.h" #include "KisChangeCloneLayersCommand.h" struct KisDlgChangeCloneSource::Private { + Private(QList layers, KisViewManager *view) + : cloneLayers(layers) + , view(view) + , image(view->image()) + , applicator(new KisProcessingApplicator(image, 0, + KisProcessingApplicator::NONE, + /* emitSignals */ KisImageSignalVector() << ModifiedSignal, + kundo2_i18n("Change Clone Layers"))) + , lastCommand(0) {} + QList cloneLayers; KisViewManager *view; KisImageSP image; QList validTargets; Ui::WdgChangeCloneSource ui; - KisNodeSP rootNode; - KisProcessingApplicator *applicator; + QScopedPointer applicator; KUndo2Command *lastCommand; - bool canUpdateApplicator; void addToTargetListRecursively(KisNodeSP node, bool addSelf = true); void filterOutAncestorsAndClonesRecursively(KisLayerSP layer); - void createApplicator(); KisLayerSP getSelectedTargetLayer(); KUndo2Command *createCommand(KisLayerSP targetLayer); }; void KisDlgChangeCloneSource::Private::addToTargetListRecursively(KisNodeSP node, bool addSelf) { if (!node) { return; } if (addSelf) { KisLayerSP layer(qobject_cast(node.data())); if (layer) { validTargets << layer; } } for (KisNodeSP childNode = node->lastChild(); childNode; childNode = childNode->prevSibling()) { KisLayerSP childLayer(qobject_cast(childNode.data())); if (childLayer) { addToTargetListRecursively(childLayer); } } } void KisDlgChangeCloneSource::Private::filterOutAncestorsAndClonesRecursively(KisLayerSP layer) { validTargets.removeOne(layer); // remove `layer` and its ancestors KisLayerSP parent = qobject_cast(layer->parent().data()); if (parent) { filterOutAncestorsAndClonesRecursively(parent); } // remove all clones of `layer`, and their ancestors Q_FOREACH (KisCloneLayerSP clone, layer->registeredClones()) { filterOutAncestorsAndClonesRecursively(clone); } } -void KisDlgChangeCloneSource::Private::createApplicator() -{ - delete applicator; - - KisImageSignalVector emitSignals; - emitSignals << ModifiedSignal; - - applicator = new KisProcessingApplicator(image, 0, - KisProcessingApplicator::NONE, - emitSignals, - kundo2_i18n("Change Clone Layers")); -} - KisLayerSP KisDlgChangeCloneSource::Private::getSelectedTargetLayer() { int index = ui.cmbSourceLayer->currentIndex(); if (index != -1) { return validTargets.at(index); } else { return 0; } } KUndo2Command *KisDlgChangeCloneSource::Private::createCommand(KisLayerSP targetLayer) { lastCommand = new KisChangeCloneLayersCommand(cloneLayers, targetLayer); return lastCommand; } KisDlgChangeCloneSource::KisDlgChangeCloneSource(QList layers, KisViewManager *view, QWidget *parent) : KoDialog(parent) - , d(new Private()) + , d(new Private(layers, view)) { KIS_SAFE_ASSERT_RECOVER_RETURN(!layers.isEmpty()); - d->cloneLayers = layers; - d->view = view; - d->image = d->view->image(); - d->createApplicator(); - d->canUpdateApplicator = false; - - connect(d->image, &KisImage::sigStrokeCancellationRequested, - this, &KisDlgChangeCloneSource::closeAndReject); - connect(d->image, &KisImage::sigUndoDuringStrokeRequested, - this, &KisDlgChangeCloneSource::closeAndReject); - connect(d->image, &KisImage::sigStrokeEndRequested, - this, &KisDlgChangeCloneSource::closeAndAccept); - - connect(this, &KisDlgChangeCloneSource::accepted, - this, &KisDlgChangeCloneSource::slotEndOrUndoChanges); - connect(this, &KisDlgChangeCloneSource::rejected, - this, &KisDlgChangeCloneSource::slotEndOrUndoChanges); + + connect(d->image.data(), &KisImage::sigStrokeCancellationRequested, + this, &KisDlgChangeCloneSource::reject); + connect(d->image.data(), &KisImage::sigUndoDuringStrokeRequested, + this, &KisDlgChangeCloneSource::reject); + connect(d->image.data(), &KisImage::sigStrokeEndRequested, + this, &KisDlgChangeCloneSource::accept); setButtons(Ok | Cancel); setDefaultButton(Ok); QWidget *widget = new QWidget(this); d->ui.setupUi(widget); setMainWidget(widget); connect(d->ui.cmbSourceLayer, QOverload::of(&QComboBox::currentIndexChanged), this, &KisDlgChangeCloneSource::slotCancelChangesAndSetNewTarget); updateTargetLayerList(); } KisDlgChangeCloneSource::~KisDlgChangeCloneSource() { dbgUI << "dialog destroyed"; - delete d->applicator; + if (d->applicator) { + if (result() == QDialog::Accepted && d->lastCommand) { + dbgUI << "Accepted"; + d->applicator->end(); + } else { // if the user never changed it, no need to make another undo command + dbgUI << "Rejected"; + d->applicator->cancel(); + } + } } void KisDlgChangeCloneSource::updateTargetLayerList() { - KisImageWSP image = d->view->image(); + KisSignalsBlocker b(d->ui.cmbSourceLayer); + + KisImageSP image = d->image; if (!image) { return; } KisNodeSP root = image->root(); - d->rootNode = root; d->validTargets.clear(); d->addToTargetListRecursively(root, /* addSelf = */ false); KisLayerSP commonCopyFrom(d->cloneLayers.first()->copyFrom()); Q_FOREACH (KisCloneLayerSP clone, d->cloneLayers) { // filter out invalid targets: // selected clone layers, their ancestors; // the clone layers' registered clone, the clones' ancestors. d->filterOutAncestorsAndClonesRecursively(clone); // assume that clone->copyFrom() != 0 if (clone->copyFrom() != commonCopyFrom) { commonCopyFrom = 0; } } d->ui.cmbSourceLayer->clear(); Q_FOREACH (KisNodeSP node, d->validTargets) { d->ui.cmbSourceLayer->addItem(node->name()); } - d->canUpdateApplicator = false; - if (commonCopyFrom) { d->ui.cmbSourceLayer->setCurrentIndex(d->validTargets.indexOf(commonCopyFrom)); } else { d->ui.cmbSourceLayer->setCurrentIndex(-1); } - - d->canUpdateApplicator = true; } void KisDlgChangeCloneSource::slotCancelChangesAndSetNewTarget() { - // if lastCommand is empty, it means the user never selected a target - if (d->lastCommand) { - d->applicator->cancel(); - d->createApplicator(); - } - if (d->canUpdateApplicator) { - KisLayerSP targetLayer = d->getSelectedTargetLayer(); - if (targetLayer) { - d->applicator->applyCommand(d->createCommand(targetLayer)); - } - } -} - -void KisDlgChangeCloneSource::slotEndOrUndoChanges() -{ - disconnect(this, &KisDlgChangeCloneSource::accepted, - this, &KisDlgChangeCloneSource::slotEndOrUndoChanges); - disconnect(this, &KisDlgChangeCloneSource::rejected, - this, &KisDlgChangeCloneSource::slotEndOrUndoChanges); - if (result() == QDialog::Accepted && d->lastCommand) { - dbgUI << "Accepted"; - d->applicator->end(); - } else { // if the user never changed it, no need to make another undo command - dbgUI << "Rejected"; - d->applicator->cancel(); + KisLayerSP targetLayer = d->getSelectedTargetLayer(); + if (targetLayer) { + d->applicator->applyCommand(d->createCommand(targetLayer)); } } -void KisDlgChangeCloneSource::closeAndAccept() -{ - done(QDialog::Accepted); -} - -void KisDlgChangeCloneSource::closeAndReject() -{ - done(QDialog::Rejected); -} diff --git a/libs/ui/dialogs/KisDlgChangeCloneSource.h b/libs/ui/dialogs/KisDlgChangeCloneSource.h index eb0e601f2b..3957a40d6e 100644 --- a/libs/ui/dialogs/KisDlgChangeCloneSource.h +++ b/libs/ui/dialogs/KisDlgChangeCloneSource.h @@ -1,53 +1,50 @@ /* * Copyright (c) 2019 Tusooa Zhu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_DLG_CHANGE_CLONE_SOURCE_H_ #define KIS_DLG_CHANGE_CLONE_SOURCE_H_ #include "kis_types.h" #include #include "ui_wdgchangeclonesource.h" class QWidget; class KisViewManager; class KisDlgChangeCloneSource : public KoDialog { Q_OBJECT public: KisDlgChangeCloneSource(QList layers, KisViewManager *view, QWidget *parent = 0); ~KisDlgChangeCloneSource() override; private: void updateTargetLayerList(); -private Q_SLOTS: +public Q_SLOTS: void slotCancelChangesAndSetNewTarget(); - void slotEndOrUndoChanges(); - void closeAndAccept(); - void closeAndReject(); private: struct Private; const QScopedPointer d; }; #endif // KIS_DLG_CHANGE_CLONE_SOURCE_H_