File indexing completed on 2024-05-26 04:32:28
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "timeline_node_list_keeper.h" 0008 0009 #include "kis_node_dummies_graph.h" 0010 #include "kis_dummies_facade_base.h" 0011 #include "timeline_frames_index_converter.h" 0012 0013 #include <QSet> 0014 #include "kis_keyframe_channel.h" 0015 #include "KisNodeDisplayModeAdapter.h" 0016 #include "kis_signal_auto_connection.h" 0017 0018 struct TimelineNodeListKeeper::Private 0019 { 0020 Private(TimelineNodeListKeeper *_q, 0021 ModelWithExternalNotifications *_model, 0022 KisDummiesFacadeBase *_dummiesFacade, 0023 KisNodeDisplayModeAdapter *_displayModeAdapter) 0024 : q(_q), 0025 model(_model), 0026 dummiesFacade(_dummiesFacade), 0027 displayModeAdapter(_displayModeAdapter), 0028 showGlobalSelectionMask(_displayModeAdapter->showGlobalSelectionMask()), 0029 converter(dummiesFacade) 0030 { 0031 converter.setShowGlobalSelectionMask(showGlobalSelectionMask); 0032 } 0033 0034 TimelineNodeListKeeper *q; 0035 ModelWithExternalNotifications *model; 0036 KisDummiesFacadeBase *dummiesFacade; 0037 KisNodeDisplayModeAdapter *displayModeAdapter; 0038 bool showGlobalSelectionMask; 0039 0040 TimelineFramesIndexConverter converter; 0041 0042 QVector<KisNodeDummy*> dummiesList; 0043 QSet<KisNodeDummy*> connectionsSet; 0044 KisSignalAutoConnectionsStore channelConnectionsStore; 0045 0046 void populateDummiesList() { 0047 const int rowCount = converter.rowCount(); 0048 for (int i = 0; i < rowCount; ++i) { 0049 KisNodeDummy *dummy = converter.dummyFromRow(i); 0050 0051 dummiesList.append(dummy); 0052 tryConnectDummy(dummy); 0053 } 0054 } 0055 0056 void tryConnectDummy(KisNodeDummy *dummy); 0057 void disconnectDummy(KisNodeDummy *dummy); 0058 0059 void findOtherLayers(KisNodeDummy *root, 0060 TimelineNodeListKeeper::OtherLayersList *list, 0061 const QString &prefix); 0062 0063 }; 0064 0065 TimelineNodeListKeeper::TimelineNodeListKeeper(ModelWithExternalNotifications *model, 0066 KisDummiesFacadeBase *dummiesFacade, 0067 KisNodeDisplayModeAdapter *displayModeAdapter) 0068 : m_d(new Private(this, model, dummiesFacade, displayModeAdapter)) 0069 { 0070 KIS_ASSERT_RECOVER_RETURN(m_d->dummiesFacade); 0071 0072 connect(m_d->dummiesFacade, SIGNAL(sigEndInsertDummy(KisNodeDummy*)), 0073 SLOT(slotEndInsertDummy(KisNodeDummy*))); 0074 connect(m_d->dummiesFacade, SIGNAL(sigBeginRemoveDummy(KisNodeDummy*)), 0075 SLOT(slotBeginRemoveDummy(KisNodeDummy*))); 0076 connect(m_d->dummiesFacade, SIGNAL(sigDummyChanged(KisNodeDummy*)), 0077 SLOT(slotDummyChanged(KisNodeDummy*))); 0078 0079 m_d->populateDummiesList(); 0080 0081 connect(m_d->displayModeAdapter, SIGNAL(sigNodeDisplayModeChanged(bool, bool)), SLOT(slotDisplayModeChanged())); 0082 } 0083 0084 TimelineNodeListKeeper::~TimelineNodeListKeeper() 0085 { 0086 } 0087 0088 KisNodeDummy* TimelineNodeListKeeper::dummyFromRow(int row) 0089 { 0090 if (row >= 0 && row < m_d->dummiesList.size()) { 0091 return m_d->dummiesList[row]; 0092 } 0093 0094 return 0; 0095 } 0096 0097 int TimelineNodeListKeeper::rowForDummy(KisNodeDummy *dummy) 0098 { 0099 return m_d->dummiesList.indexOf(dummy); 0100 } 0101 0102 int TimelineNodeListKeeper::rowCount() 0103 { 0104 return m_d->dummiesList.size(); 0105 } 0106 0107 void TimelineNodeListKeeper::updateActiveDummy(KisNodeDummy *dummy) 0108 { 0109 bool oldRemoved = false; 0110 bool newAdded = false; 0111 0112 KisNodeDummy *oldActiveDummy = m_d->converter.activeDummy(); 0113 m_d->converter.updateActiveDummy(dummy, &oldRemoved, &newAdded); 0114 0115 if (oldRemoved) { 0116 slotBeginRemoveDummy(oldActiveDummy); 0117 } 0118 0119 if (newAdded) { 0120 slotEndInsertDummy(dummy); 0121 } 0122 } 0123 0124 void TimelineNodeListKeeper::slotUpdateDummyContent(QPointer<KisNodeDummy> dummy) 0125 { 0126 /** 0127 * The dummy object has been destroyed in the meantime, while the 0128 * event was hanging in the queue. We shouldn't try to dereference/update 0129 * it anymore, since the whole layer has already been removed 0130 */ 0131 if (!dummy) return; 0132 0133 int pos = m_d->converter.rowForDummy(dummy); 0134 if (pos < 0) return; 0135 0136 QModelIndex index0 = m_d->model->index(pos, 0); 0137 QModelIndex index1 = m_d->model->index(pos, m_d->model->columnCount() - 1); 0138 m_d->model->callIndexChanged(index0, index1); 0139 } 0140 0141 void TimelineNodeListKeeper::Private::tryConnectDummy(KisNodeDummy *dummy) 0142 { 0143 QMap<QString, KisKeyframeChannel*> channels = dummy->node()->keyframeChannels(); 0144 0145 if (channels.isEmpty()) { 0146 if (connectionsSet.contains(dummy)) { 0147 connectionsSet.remove(dummy); 0148 } 0149 0150 return; 0151 } 0152 0153 if (connectionsSet.contains(dummy)) return; 0154 0155 QPointer<KisNodeDummy> safeDummyPointer(dummy); 0156 0157 Q_FOREACH(KisKeyframeChannel *channel, channels) { 0158 channelConnectionsStore.addConnection(channel, &KisKeyframeChannel::sigAnyKeyframeChange, 0159 q, 0160 [this, safeDummyPointer ] () { 0161 // make sure that the pointer is invalidated when 0162 // the dummy is destroyed, it might happen on 0163 // reordering of the signals 0164 q->slotUpdateDummyContent(safeDummyPointer); 0165 }); 0166 } 0167 connectionsSet.insert(dummy); 0168 } 0169 0170 void TimelineNodeListKeeper::Private::disconnectDummy(KisNodeDummy *dummy) 0171 { 0172 if (!connectionsSet.contains(dummy)) return; 0173 0174 QMap<QString, KisKeyframeChannel*> channels = dummy->node()->keyframeChannels(); 0175 0176 if (channels.isEmpty()) { 0177 if (connectionsSet.contains(dummy)) { 0178 connectionsSet.remove(dummy); 0179 } 0180 return; 0181 } 0182 0183 Q_FOREACH(KisKeyframeChannel *channel, channels) { 0184 channelConnectionsStore.clear(); 0185 } 0186 0187 connectionsSet.remove(dummy); 0188 } 0189 0190 void TimelineNodeListKeeper::slotEndInsertDummy(KisNodeDummy *dummy) 0191 { 0192 KIS_ASSERT_RECOVER_RETURN(!m_d->dummiesList.contains(dummy)); 0193 0194 if (m_d->converter.isDummyVisible(dummy)) { 0195 int pos = m_d->converter.rowForDummy(dummy); 0196 0197 m_d->model->callBeginInsertRows(QModelIndex(), pos, pos); 0198 m_d->dummiesList.insert(pos, 1, dummy); 0199 m_d->tryConnectDummy(dummy); 0200 m_d->model->callEndInsertRows(); 0201 } 0202 } 0203 0204 void TimelineNodeListKeeper::slotBeginRemoveDummy(KisNodeDummy *dummy) 0205 { 0206 if (m_d->dummiesList.contains(dummy)) { 0207 int pos = m_d->dummiesList.indexOf(dummy); 0208 0209 m_d->model->callBeginRemoveRows(QModelIndex(), pos, pos); 0210 m_d->disconnectDummy(dummy); 0211 m_d->dummiesList.remove(pos); 0212 m_d->model->callEndRemoveRows(); 0213 } 0214 0215 m_d->converter.notifyDummyRemoved(dummy); 0216 } 0217 0218 void TimelineNodeListKeeper::slotDummyChanged(KisNodeDummy *dummy) 0219 { 0220 const bool present = m_d->dummiesList.contains(dummy); 0221 const bool shouldBe = m_d->converter.isDummyVisible(dummy); 0222 0223 m_d->tryConnectDummy(dummy); 0224 0225 if (!present && shouldBe) { 0226 slotEndInsertDummy(dummy); 0227 } else if (present && !shouldBe) { 0228 slotBeginRemoveDummy(dummy); 0229 } 0230 } 0231 0232 void TimelineNodeListKeeper::slotDisplayModeChanged() 0233 { 0234 if (m_d->showGlobalSelectionMask != m_d->displayModeAdapter->showGlobalSelectionMask()) { 0235 0236 m_d->model->callBeginResetModel(); 0237 0238 Q_FOREACH (KisNodeDummy *dummy, m_d->dummiesList) { 0239 m_d->disconnectDummy(dummy); 0240 } 0241 m_d->dummiesList.clear(); 0242 0243 m_d->showGlobalSelectionMask = m_d->displayModeAdapter->showGlobalSelectionMask(); 0244 m_d->converter.setShowGlobalSelectionMask(m_d->showGlobalSelectionMask); 0245 0246 m_d->populateDummiesList(); 0247 0248 m_d->model->callEndResetModel(); 0249 } 0250 } 0251 0252 void TimelineNodeListKeeper::Private::findOtherLayers(KisNodeDummy *root, 0253 TimelineNodeListKeeper::OtherLayersList *list, 0254 const QString &prefix) 0255 { 0256 KisNodeSP node = root->node(); 0257 0258 if (converter.isDummyAvailableForTimeline(root) && 0259 !root->node()->isPinnedToTimeline()) { 0260 0261 *list << 0262 TimelineNodeListKeeper::OtherLayer( 0263 QString(prefix + node->name()), 0264 root); 0265 } 0266 0267 KisNodeDummy *dummy = root->lastChild(); 0268 while(dummy) { 0269 findOtherLayers(dummy, list, prefix + " "); 0270 dummy = dummy->prevSibling(); 0271 } 0272 } 0273 0274 TimelineNodeListKeeper::OtherLayersList 0275 TimelineNodeListKeeper::otherLayersList() const 0276 { 0277 OtherLayersList list; 0278 0279 KisNodeDummy *rootDummy = m_d->dummiesFacade->rootDummy(); 0280 if (!rootDummy) return list; 0281 0282 m_d->findOtherLayers(rootDummy, &list, ""); 0283 return list; 0284 }