File indexing completed on 2024-05-19 04:54:23
0001 /* 0002 SPDX-FileCopyrightText: 2017 Nicolas Carion 0003 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 #include "effectitemmodel.hpp" 0007 0008 #include "core.h" 0009 #include "effects/effectsrepository.hpp" 0010 #include "effectstackmodel.hpp" 0011 #include <utility> 0012 0013 EffectItemModel::EffectItemModel(const QList<QVariant> &effectData, std::unique_ptr<Mlt::Properties> effect, const QDomElement &xml, const QString &effectId, 0014 const std::shared_ptr<AbstractTreeModel> &stack, bool isEnabled, QString originalDecimalPoint) 0015 : AbstractEffectItem(EffectItemType::Effect, effectData, stack, false, isEnabled) 0016 , AssetParameterModel(std::move(effect), xml, effectId, std::static_pointer_cast<EffectStackModel>(stack)->getOwnerId(), originalDecimalPoint) 0017 , m_childId(0) 0018 { 0019 connect(this, &AssetParameterModel::updateChildren, [&](const QStringList &names) { 0020 if (m_childEffects.size() == 0) { 0021 return; 0022 } 0023 // qDebug() << "* * *SETTING EFFECT PARAM: " << name << " = " << m_asset->get(name.toUtf8().constData()); 0024 QMapIterator<int, std::shared_ptr<EffectItemModel>> i(m_childEffects); 0025 while (i.hasNext()) { 0026 i.next(); 0027 for (const QString &name : names) { 0028 i.value()->filter().set(name.toUtf8().constData(), m_asset->get(name.toUtf8().constData())); 0029 } 0030 } 0031 }); 0032 } 0033 0034 // static 0035 std::shared_ptr<EffectItemModel> EffectItemModel::construct(const QString &effectId, std::shared_ptr<AbstractTreeModel> stack, bool effectEnabled) 0036 { 0037 Q_ASSERT(EffectsRepository::get()->exists(effectId)); 0038 QDomElement xml = EffectsRepository::get()->getXml(effectId); 0039 0040 std::unique_ptr<Mlt::Properties> effect = EffectsRepository::get()->getEffect(effectId); 0041 effect->set("kdenlive_id", effectId.toUtf8().constData()); 0042 0043 QList<QVariant> data; 0044 data << EffectsRepository::get()->getName(effectId) << effectId; 0045 0046 std::shared_ptr<EffectItemModel> self(new EffectItemModel(data, std::move(effect), xml, effectId, stack, effectEnabled)); 0047 0048 baseFinishConstruct(self); 0049 return self; 0050 } 0051 0052 std::shared_ptr<EffectItemModel> EffectItemModel::construct(std::unique_ptr<Mlt::Properties> effect, std::shared_ptr<AbstractTreeModel> stack, 0053 const QString &originalDecimalPoint) 0054 { 0055 QString effectId = effect->get("kdenlive_id"); 0056 if (effectId.isEmpty()) { 0057 effectId = effect->get("mlt_service"); 0058 } 0059 Q_ASSERT(EffectsRepository::get()->exists(effectId)); 0060 0061 // Get the effect XML and add parameter values from the project file 0062 QDomElement xml = EffectsRepository::get()->getXml(effectId); 0063 QDomNodeList params = xml.elementsByTagName(QStringLiteral("parameter")); 0064 for (int i = 0; i < params.count(); ++i) { 0065 QDomElement currentParameter = params.item(i).toElement(); 0066 QString paramName = currentParameter.attribute(QStringLiteral("name")); 0067 QString paramType = currentParameter.attribute(QStringLiteral("type")); 0068 if (paramType == QLatin1String("multiswitch")) { 0069 // multiswitch params have a composited param name, skip 0070 QStringList names = paramName.split(QLatin1Char('\n')); 0071 QStringList paramValues; 0072 for (const QString &n : qAsConst(names)) { 0073 paramValues << effect->get(n.toUtf8().constData()); 0074 } 0075 currentParameter.setAttribute(QStringLiteral("value"), paramValues.join(QLatin1Char('\n'))); 0076 continue; 0077 } 0078 QString paramValue = effect->get(paramName.toUtf8().constData()); 0079 qDebug() << effectId << ": Setting parameter " << paramName << " to " << paramValue; 0080 currentParameter.setAttribute(QStringLiteral("value"), paramValue); 0081 } 0082 0083 QList<QVariant> data; 0084 data << EffectsRepository::get()->getName(effectId) << effectId; 0085 0086 bool disable = effect->get_int("disable") == 0; 0087 std::shared_ptr<EffectItemModel> self(new EffectItemModel(data, std::move(effect), xml, effectId, stack, disable, originalDecimalPoint)); 0088 baseFinishConstruct(self); 0089 return self; 0090 } 0091 0092 void EffectItemModel::plant(const std::weak_ptr<Mlt::Service> &service) 0093 { 0094 if (auto ptr = service.lock()) { 0095 int ret = ptr->attach(filter()); 0096 Q_ASSERT(ret == 0); 0097 } else { 0098 qDebug() << "Error : Cannot plant effect because parent service is not available anymore"; 0099 Q_ASSERT(false); 0100 } 0101 } 0102 0103 void EffectItemModel::loadClone(const std::weak_ptr<Mlt::Service> &service) 0104 { 0105 if (auto ptr = service.lock()) { 0106 std::shared_ptr<EffectItemModel> effect = nullptr; 0107 for (int i = 0; i < ptr->filter_count(); i++) { 0108 std::unique_ptr<Mlt::Filter> filt(ptr->filter(i)); 0109 QString effName = filt->get("kdenlive_id"); 0110 if (effName == m_assetId && filt->get_int("_kdenlive_processed") == 0) { 0111 if (auto ptr2 = m_model.lock()) { 0112 effect = EffectItemModel::construct(std::move(filt), ptr2, QString()); 0113 int childId = ptr->get_int("_childid"); 0114 if (childId == 0) { 0115 childId = m_childId++; 0116 ptr->set("_childid", childId); 0117 } 0118 m_childEffects.insert(childId, effect); 0119 } 0120 break; 0121 } 0122 filt->set("_kdenlive_processed", 1); 0123 } 0124 return; 0125 } 0126 qDebug() << "Error : Cannot plant effect because parent service is not available anymore"; 0127 Q_ASSERT(false); 0128 } 0129 0130 void EffectItemModel::plantClone(const std::weak_ptr<Mlt::Service> &service) 0131 { 0132 if (auto ptr = service.lock()) { 0133 const QString effectId = getAssetId(); 0134 std::shared_ptr<EffectItemModel> effect = nullptr; 0135 if (auto ptr2 = m_model.lock()) { 0136 effect = EffectItemModel::construct(effectId, ptr2); 0137 effect->setParameters(getAllParameters(), false); 0138 int childId = ptr->get_int("_childid"); 0139 if (childId == 0) { 0140 childId = m_childId++; 0141 ptr->set("_childid", childId); 0142 } 0143 m_childEffects.insert(childId, effect); 0144 int ret = ptr->attach(effect->filter()); 0145 Q_ASSERT(ret == 0); 0146 return; 0147 } 0148 } 0149 qDebug() << "Error : Cannot plant effect because parent service is not available anymore"; 0150 Q_ASSERT(false); 0151 } 0152 0153 void EffectItemModel::unplant(const std::weak_ptr<Mlt::Service> &service) 0154 { 0155 if (auto ptr = service.lock()) { 0156 int ret = ptr->detach(filter()); 0157 Q_ASSERT(ret == 0); 0158 } else { 0159 qDebug() << "Error : Cannot plant effect because parent service is not available anymore"; 0160 Q_ASSERT(false); 0161 } 0162 } 0163 0164 void EffectItemModel::unplantClone(const std::weak_ptr<Mlt::Service> &service) 0165 { 0166 if (m_childEffects.size() == 0) { 0167 return; 0168 } 0169 if (auto ptr = service.lock()) { 0170 int ret = ptr->detach(filter()); 0171 Q_ASSERT(ret == 0); 0172 int childId = ptr->get_int("_childid"); 0173 auto effect = m_childEffects.take(childId); 0174 if (effect && effect->isValid()) { 0175 ptr->detach(effect->filter()); 0176 effect.reset(); 0177 } 0178 } else { 0179 qDebug() << "Error : Cannot plant effect because parent service is not available anymore"; 0180 Q_ASSERT(false); 0181 } 0182 } 0183 0184 Mlt::Filter &EffectItemModel::filter() const 0185 { 0186 return *static_cast<Mlt::Filter *>(m_asset.get()); 0187 } 0188 0189 bool EffectItemModel::isValid() const 0190 { 0191 return m_asset && m_asset->is_valid(); 0192 } 0193 0194 void EffectItemModel::updateEnable(bool updateTimeline) 0195 { 0196 filter().set("disable", isEnabled() ? 0 : 1); 0197 if (updateTimeline) { 0198 pCore->refreshProjectItem(m_ownerId); 0199 pCore->invalidateItem(m_ownerId); 0200 } 0201 const QModelIndex start = AssetParameterModel::index(0, 0); 0202 const QModelIndex end = AssetParameterModel::index(rowCount() - 1, 0); 0203 Q_EMIT dataChanged(start, end, QVector<int>()); 0204 Q_EMIT enabledChange(!isEnabled()); 0205 // Update timeline child producers 0206 Q_EMIT AssetParameterModel::updateChildren({QStringLiteral("disable")}); 0207 } 0208 0209 void EffectItemModel::setCollapsed(bool collapsed) 0210 { 0211 filter().set("kdenlive:collapsed", collapsed ? 1 : 0); 0212 } 0213 0214 bool EffectItemModel::isCollapsed() const 0215 { 0216 return filter().get_int("kdenlive:collapsed") == 1; 0217 } 0218 0219 void EffectItemModel::setKeyframesHidden(bool hidden) 0220 { 0221 Fun undo = [this, hidden]() { 0222 filter().set("kdenlive:kfrhidden", hidden ? 0 : 1); 0223 Q_EMIT hideKeyframesChange(hidden ? false : true); 0224 return true; 0225 }; 0226 Fun redo = [this, hidden]() { 0227 filter().set("kdenlive:kfrhidden", hidden ? 1 : 0); 0228 Q_EMIT hideKeyframesChange(hidden ? true : false); 0229 return true; 0230 }; 0231 redo(); 0232 pCore->pushUndo(undo, redo, hidden ? i18n("Hide keyframes") : i18n("Show keyframes")); 0233 } 0234 0235 bool EffectItemModel::isKeyframesHidden() const 0236 { 0237 return filter().get_int("kdenlive:kfrhidden") == 1; 0238 } 0239 0240 bool EffectItemModel::keyframesHiddenUnset() const 0241 { 0242 return filter().property_exists("kdenlive:kfrhidden") == false; 0243 } 0244 0245 bool EffectItemModel::hasForcedInOut() const 0246 { 0247 return filter().get_int("kdenlive:force_in_out") == 1; 0248 } 0249 0250 bool EffectItemModel::isAudio() const 0251 { 0252 return EffectsRepository::get()->isAudioEffect(m_assetId); 0253 } 0254 0255 bool EffectItemModel::isUnique() const 0256 { 0257 return EffectsRepository::get()->isUnique(m_assetId); 0258 } 0259 0260 QPair<int, int> EffectItemModel::getInOut() const 0261 { 0262 return {m_asset->get_int("in"), m_asset->get_int("out")}; 0263 } 0264 0265 void EffectItemModel::setInOut(const QString &effectName, QPair<int, int> bounds, bool enabled, bool withUndo) 0266 { 0267 QPair<int, int> currentInOut = {m_asset->get_int("in"), m_asset->get_int("out")}; 0268 int currentState = m_asset->get_int("kdenlive:force_in_out"); 0269 Fun undo = [this, currentState, currentInOut]() { 0270 m_asset->set("kdenlive:force_in_out", currentState); 0271 m_asset->set("in", currentInOut.first); 0272 m_asset->set("out", currentInOut.second); 0273 Q_EMIT AssetParameterModel::updateChildren({QStringLiteral("in"), QStringLiteral("out")}); 0274 if (!isAudio()) { 0275 pCore->refreshProjectItem(m_ownerId); 0276 pCore->invalidateItem(m_ownerId); 0277 } 0278 Q_EMIT showEffectZone(m_ownerId, currentInOut, currentState == 1); 0279 return true; 0280 }; 0281 Fun redo = [this, enabled, bounds]() { 0282 m_asset->set("kdenlive:force_in_out", enabled ? 1 : 0); 0283 m_asset->set("in", bounds.first); 0284 m_asset->set("out", bounds.second); 0285 Q_EMIT AssetParameterModel::updateChildren({QStringLiteral("in"), QStringLiteral("out")}); 0286 if (!isAudio()) { 0287 pCore->refreshProjectItem(m_ownerId); 0288 pCore->invalidateItem(m_ownerId); 0289 } 0290 Q_EMIT showEffectZone(m_ownerId, bounds, enabled); 0291 return true; 0292 }; 0293 std::shared_ptr<KeyframeModelList> keyframes = getKeyframeModel(); 0294 if (keyframes != nullptr) { 0295 // Effect has keyframes, update these 0296 const QModelIndex start = AssetParameterModel::index(0, 0); 0297 const QModelIndex end = AssetParameterModel::index(rowCount() - 1, 0); 0298 Fun refresh = [this, start, end]() { 0299 Q_EMIT dataChanged(start, end, QVector<int>()); 0300 return true; 0301 }; 0302 refresh(); 0303 PUSH_LAMBDA(refresh, redo); 0304 PUSH_LAMBDA(refresh, undo); 0305 } 0306 redo(); 0307 if (withUndo) { 0308 pCore->pushUndo(undo, redo, i18n("Update zone for %1", effectName)); 0309 } 0310 }