File indexing completed on 2024-10-27 04:07:33
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_dummies_facade_base.h" 0008 0009 #include "kis_image.h" 0010 #include "kis_node_dummies_graph.h" 0011 #include "kis_layer_utils.h" 0012 #include <KisSynchronizedConnection.h> 0013 0014 struct KisDummiesFacadeBase::Private 0015 { 0016 public: 0017 KisImageWSP image; 0018 KisNodeSP savedRootNode; 0019 0020 KisSynchronizedConnection<KisNodeSP> activateNodeConnection; 0021 KisSynchronizedConnection<KisNodeSP> nodeChangedConnection; 0022 KisSynchronizedConnection<KisNodeSP,KisNodeSP,KisNodeSP> addNodeConnection; 0023 KisSynchronizedConnection<KisNodeSP> removeNodeConnection; 0024 0025 /** 0026 * pendingNodeSet contains the set of nodes that will be present in the 0027 * dummies graph after all the synchronized events are processed by the GUI 0028 * thread. This set is used to reset the graph when the image changes its root 0029 * during the 'flatten' operation. 0030 */ 0031 QList<KisNodeSP> pendingNodeSet; 0032 QMutex pendingNodeSetLock; 0033 }; 0034 0035 0036 KisDummiesFacadeBase::KisDummiesFacadeBase(QObject *parent) 0037 : QObject(parent), 0038 m_d(new Private()) 0039 { 0040 m_d->activateNodeConnection.connectOutputSlot(this, &KisDummiesFacadeBase::slotNodeActivationRequested); 0041 m_d->nodeChangedConnection.connectOutputSlot(this, &KisDummiesFacadeBase::slotNodeChanged); 0042 m_d->addNodeConnection.connectOutputSlot(this, &KisDummiesFacadeBase::slotContinueAddNode); 0043 m_d->removeNodeConnection.connectOutputSlot(this, &KisDummiesFacadeBase::slotContinueRemoveNode); 0044 } 0045 0046 KisDummiesFacadeBase::~KisDummiesFacadeBase() 0047 { 0048 delete m_d; 0049 } 0050 0051 void KisDummiesFacadeBase::setImage(KisImageWSP image) 0052 { 0053 if (m_d->image) { 0054 emit sigActivateNode(0); 0055 m_d->image->disconnect(this); 0056 m_d->image->disconnect(&m_d->nodeChangedConnection); 0057 m_d->image->disconnect(&m_d->activateNodeConnection); 0058 0059 KisNodeList nodesToRemove; 0060 0061 { 0062 QMutexLocker l(&m_d->pendingNodeSetLock); 0063 std::swap(nodesToRemove, m_d->pendingNodeSet); 0064 m_d->pendingNodeSet.clear(); 0065 } 0066 0067 for (auto it = std::make_reverse_iterator(nodesToRemove.end()); 0068 it != std::make_reverse_iterator(nodesToRemove.begin()); 0069 ++it) { 0070 0071 m_d->removeNodeConnection.start(*it); 0072 } 0073 } 0074 0075 m_d->image = image; 0076 0077 if (image) { 0078 slotNodeAdded(image->root()); 0079 0080 connect(image, SIGNAL(sigNodeAddedAsync(KisNodeSP)), 0081 SLOT(slotNodeAdded(KisNodeSP)), Qt::DirectConnection); 0082 connect(image, SIGNAL(sigRemoveNodeAsync(KisNodeSP)), 0083 SLOT(slotRemoveNode(KisNodeSP)), Qt::DirectConnection); 0084 connect(image, SIGNAL(sigLayersChangedAsync()), 0085 SLOT(slotLayersChanged()), Qt::DirectConnection); 0086 0087 m_d->nodeChangedConnection.connectInputSignal(image, &KisImage::sigNodeChanged); 0088 m_d->activateNodeConnection.connectInputSignal(image, &KisImage::sigNodeAddedAsync); 0089 0090 m_d->activateNodeConnection.start(findFirstLayer(image->root())); 0091 } 0092 } 0093 0094 KisImageWSP KisDummiesFacadeBase::image() const 0095 { 0096 return m_d->image; 0097 } 0098 0099 KisNodeSP KisDummiesFacadeBase::findFirstLayer(KisNodeSP root) 0100 { 0101 KisNodeSP child = root->firstChild(); 0102 while(child && !child->inherits("KisLayer")) { 0103 child = child->nextSibling(); 0104 } 0105 return child; 0106 } 0107 0108 void KisDummiesFacadeBase::slotNodeChanged(KisNodeSP node) 0109 { 0110 KisNodeDummy *dummy = dummyForNode(node); 0111 0112 /** 0113 * In some "buggy" code the node-changed signal may be emitted 0114 * before the node will become a part of the node graph. It is 0115 * a bug, we a really minor one. It should not cause any data 0116 * losses to the user. 0117 */ 0118 KIS_SAFE_ASSERT_RECOVER_RETURN(dummy); 0119 0120 emit sigDummyChanged(dummy); 0121 } 0122 0123 void KisDummiesFacadeBase::slotLayersChanged() 0124 { 0125 setImage(m_d->image); 0126 } 0127 0128 void KisDummiesFacadeBase::slotNodeActivationRequested(KisNodeSP node) 0129 { 0130 if (!node || !node->graphListener()) return; 0131 0132 if (!node->inherits("KisSelectionMask") && 0133 !node->inherits("KisReferenceImagesLayer") && 0134 !node->inherits("KisDecorationsWrapperLayer")) { 0135 0136 emit sigActivateNode(node); 0137 } 0138 } 0139 0140 void KisDummiesFacadeBase::slotNodeAdded(KisNodeSP node) 0141 { 0142 { 0143 QMutexLocker l(&m_d->pendingNodeSetLock); 0144 m_d->pendingNodeSet.append(node); 0145 } 0146 0147 m_d->addNodeConnection.start(node, node->parent(), node->prevSibling()); 0148 0149 KisNodeSP childNode = node->firstChild(); 0150 while (childNode) { 0151 slotNodeAdded(childNode); 0152 childNode = childNode->nextSibling(); 0153 } 0154 } 0155 0156 void KisDummiesFacadeBase::slotRemoveNode(KisNodeSP node) 0157 { 0158 { 0159 QMutexLocker l(&m_d->pendingNodeSetLock); 0160 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->pendingNodeSet.contains(node)); 0161 } 0162 0163 KisNodeSP childNode = node->lastChild(); 0164 while (childNode) { 0165 slotRemoveNode(childNode); 0166 childNode = childNode->prevSibling(); 0167 } 0168 0169 { 0170 QMutexLocker l(&m_d->pendingNodeSetLock); 0171 m_d->pendingNodeSet.removeOne(node); 0172 } 0173 m_d->removeNodeConnection.start(node); 0174 } 0175 0176 void KisDummiesFacadeBase::slotContinueAddNode(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis) 0177 { 0178 KisNodeDummy *parentDummy = parent ? dummyForNode(parent) : 0; 0179 KisNodeDummy *aboveThisDummy = aboveThis ? dummyForNode(aboveThis) : 0; 0180 // Add one because this node does not exist yet 0181 int index = parentDummy && aboveThisDummy ? 0182 parentDummy->indexOf(aboveThisDummy) + 1 : 0; 0183 emit sigBeginInsertDummy(parentDummy, index, node->metaObject()->className()); 0184 0185 addNodeImpl(node, parent, aboveThis); 0186 0187 emit sigEndInsertDummy(dummyForNode(node)); 0188 } 0189 0190 void KisDummiesFacadeBase::slotContinueRemoveNode(KisNodeSP node) 0191 { 0192 KisNodeDummy *dummy = dummyForNode(node); 0193 emit sigBeginRemoveDummy(dummy); 0194 0195 removeNodeImpl(node); 0196 0197 emit sigEndRemoveDummy(); 0198 }