diff --git a/libs/ui/dialogs/KisDlgChangeCloneSource.cpp b/libs/ui/dialogs/KisDlgChangeCloneSource.cpp index 29f1fb1d25..98a159016d 100644 --- a/libs/ui/dialogs/KisDlgChangeCloneSource.cpp +++ b/libs/ui/dialogs/KisDlgChangeCloneSource.cpp @@ -1,139 +1,207 @@ /* * 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 "KisViewManager.h" #include "KisChangeCloneLayersCommand.h" struct KisDlgChangeCloneSource::Private { QList cloneLayers; KisViewManager *view; + KisImageSP image; QList validTargets; Ui::WdgChangeCloneSource ui; KisNodeSP rootNode; + KisProcessingApplicator *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()) { 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::slotCancelChangesAndSetNewTarget); + connect(d->image, &KisImage::sigUndoDuringStrokeRequested, + this, &KisDlgChangeCloneSource::slotCancelChangesAndSetNewTarget); 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() { - if (result() == QDialog::Accepted) { - int index = d->ui.cmbSourceLayer->currentIndex(); - if (index != -1) { - KisLayerSP targetLayer = d->validTargets.at(index); - KisChangeCloneLayersCommand *command = new KisChangeCloneLayersCommand(d->cloneLayers, targetLayer); - d->view->undoAdapter()->addCommand(command); - } + if (result() == QDialog::Accepted && d->lastCommand) { + d->applicator->end(); + } else { // if the user never changed it, no need to make another undo command + d->applicator->cancel(); } + delete d->applicator; } void KisDlgChangeCloneSource::updateTargetLayerList() { KisImageWSP image = d->view->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)); + } + } +} + diff --git a/libs/ui/dialogs/KisDlgChangeCloneSource.h b/libs/ui/dialogs/KisDlgChangeCloneSource.h index 3eedceeb2b..6ea7c341e3 100644 --- a/libs/ui/dialogs/KisDlgChangeCloneSource.h +++ b/libs/ui/dialogs/KisDlgChangeCloneSource.h @@ -1,47 +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: + void slotCancelChangesAndSetNewTarget(); + private: struct Private; const QScopedPointer d; }; #endif // KIS_DLG_CHANGE_CLONE_SOURCE_H_