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 }