diff --git a/src/assets/abstractassetsrepository.ipp b/src/assets/abstractassetsrepository.ipp index b10ec84ab..68f357d17 100644 --- a/src/assets/abstractassetsrepository.ipp +++ b/src/assets/abstractassetsrepository.ipp @@ -1,316 +1,318 @@ /*************************************************************************** * Copyright (C) 2017 by Nicolas Carion * * This file is part of Kdenlive. See www.kdenlive.org. * * * * 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) version 3 or any later version accepted by the * * membership of KDE e.V. (or its successor approved by the membership * * of KDE e.V.), which shall act as a proxy defined in Section 14 of * * version 3 of the license. * * * * 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, see . * ***************************************************************************/ #include "xml/xml.hpp" #include #include #include #include #include #include #ifdef Q_OS_MAC #include #endif template AbstractAssetsRepository::AbstractAssetsRepository() = default; template void AbstractAssetsRepository::init() { // Warning: Mlt::Factory::init() resets the locale to the default system value, make sure we keep correct locale #ifndef Q_OS_MAC setlocale(LC_NUMERIC, nullptr); #else setlocale(LC_NUMERIC_MASK, nullptr); #endif // Parse effects blacklist parseBlackList(assetBlackListPath()); // Retrieve the list of MLT's available assets. QScopedPointer assets(retrieveListFromMlt()); int max = assets->count(); QString sox = QStringLiteral("sox."); for (int i = 0; i < max; ++i) { Info info; QString name = assets->get_name(i); info.id = name; if (name.startsWith(sox)) { // sox effects are not usage directly (parameters not available) continue; } // qDebug() << "trying to parse " < customAssets; - for (const auto &dir : asset_dirs) { + // reverse order to prioritize local install + QListIterator dirs_it(asset_dirs); + for (dirs_it.toBack(); dirs_it.hasPrevious();) { auto dir=dirs_it.previous(); QDir current_dir(dir); QStringList filter; filter << QStringLiteral("*.xml"); QStringList fileList = current_dir.entryList(filter, QDir::Files); for (const auto &file : fileList) { QString path = current_dir.absoluteFilePath(file); parseCustomAssetFile(path, customAssets); } } // We add the custom assets for (const auto &custom : customAssets) { // Custom assets should override default ones m_assets[custom.first] = custom.second; /*if (m_assets.count(custom.second.mltId) > 0) { m_assets.erase(custom.second.mltId); } if (m_assets.count(custom.first) == 0) { m_assets[custom.first] = custom.second; } else { qDebug() << "Error: conflicting asset name " << custom.first; }*/ } } template void AbstractAssetsRepository::parseBlackList(const QString &path) { QFile blacklist_file(path); if (blacklist_file.open(QIODevice::ReadOnly)) { QTextStream stream(&blacklist_file); QString line; while (stream.readLineInto(&line)) { line = line.simplified(); if (!line.isEmpty() && !line.startsWith('#')) { m_blacklist.insert(line); } } blacklist_file.close(); } } template bool AbstractAssetsRepository::parseInfoFromMlt(const QString &assetId, Info &res) { QScopedPointer metadata(getMetadata(assetId)); if (metadata && metadata->is_valid()) { if (metadata->get("title") && metadata->get("identifier") && strlen(metadata->get("title")) > 0) { QString id = metadata->get("identifier"); res.name = metadata->get("title"); res.name[0] = res.name[0].toUpper(); res.description = metadata->get("description"); res.description.append(QString(" (%1)").arg(id)); res.author = metadata->get("creator"); res.version_str = metadata->get("version"); res.version = ceil(100 * metadata->get_double("version")); res.id = res.mltId = assetId; parseType(metadata, res); // Create params QDomDocument doc; QDomElement eff = doc.createElement(QStringLiteral("effect")); eff.setAttribute(QStringLiteral("tag"), id); eff.setAttribute(QStringLiteral("id"), id); ////qCDebug(KDENLIVE_LOG)<<"Effect: "<get_data("parameters")); for (int j = 0; param_props.is_valid() && j < param_props.count(); ++j) { QDomElement params = doc.createElement(QStringLiteral("parameter")); Mlt::Properties paramdesc((mlt_properties)param_props.get_data(param_props.get_name(j))); params.setAttribute(QStringLiteral("name"), paramdesc.get("identifier")); if (params.attribute(QStringLiteral("name")) == QLatin1String("argument")) { // This parameter has to be given as attribute when using command line, do not show it in Kdenlive continue; } if (paramdesc.get("readonly") && (strcmp(paramdesc.get("readonly"), "yes") == 0)) { // Do not expose readonly parameters continue; } if (paramdesc.get("maximum")) { params.setAttribute(QStringLiteral("max"), paramdesc.get("maximum")); } if (paramdesc.get("minimum")) { params.setAttribute(QStringLiteral("min"), paramdesc.get("minimum")); } QString paramType = paramdesc.get("type"); if (paramType == QLatin1String("integer")) { if (params.attribute(QStringLiteral("min")) == QLatin1String("0") && params.attribute(QStringLiteral("max")) == QLatin1String("1")) { params.setAttribute(QStringLiteral("type"), QStringLiteral("bool")); } else { params.setAttribute(QStringLiteral("type"), QStringLiteral("constant")); } } else if (paramType == QLatin1String("float")) { params.setAttribute(QStringLiteral("type"), QStringLiteral("constant")); // param type is float, set default decimals to 3 params.setAttribute(QStringLiteral("decimals"), QStringLiteral("3")); } else if (paramType == QLatin1String("boolean")) { params.setAttribute(QStringLiteral("type"), QStringLiteral("bool")); } else if (paramType == QLatin1String("geometry")) { params.setAttribute(QStringLiteral("type"), QStringLiteral("geometry")); } else if (paramType == QLatin1String("string")) { // string parameter are not really supported, so if we have a default value, enforce it params.setAttribute(QStringLiteral("type"), QStringLiteral("fixed")); if (paramdesc.get("default")) { QString stringDefault = paramdesc.get("default"); stringDefault.remove(QLatin1Char('\'')); params.setAttribute(QStringLiteral("value"), stringDefault); } else { // String parameter without default, skip it completely continue; } } else { params.setAttribute(QStringLiteral("type"), paramType); if (!QString(paramdesc.get("format")).isEmpty()) { params.setAttribute(QStringLiteral("format"), paramdesc.get("format")); } } if (!params.hasAttribute(QStringLiteral("value"))) { if (paramdesc.get("default")) { params.setAttribute(QStringLiteral("default"), paramdesc.get("default")); } if (paramdesc.get("value")) { params.setAttribute(QStringLiteral("value"), paramdesc.get("value")); } else { params.setAttribute(QStringLiteral("value"), paramdesc.get("default")); } } QString paramName = paramdesc.get("title"); if (!paramName.isEmpty()) { QDomElement pname = doc.createElement(QStringLiteral("name")); pname.appendChild(doc.createTextNode(paramName)); params.appendChild(pname); } if (paramdesc.get("description")) { QDomElement comment = doc.createElement(QStringLiteral("comment")); comment.appendChild(doc.createTextNode(paramdesc.get("description"))); params.appendChild(comment); } eff.appendChild(params); } doc.appendChild(eff); res.xml = eff; return true; } } return false; } template bool AbstractAssetsRepository::exists(const QString &assetId) const { return m_assets.count(assetId) > 0; } template QVector> AbstractAssetsRepository::getNames() const { QVector> res; res.reserve((int)m_assets.size()); for (const auto &asset : m_assets) { res.push_back({asset.first, asset.second.name}); } std::sort(res.begin(), res.end(), [](const QPair &a, const QPair &b) { return a.second < b.second; }); return res; } template AssetType AbstractAssetsRepository::getType(const QString &assetId) const { Q_ASSERT(m_assets.count(assetId) > 0); return m_assets.at(assetId).type; } template QString AbstractAssetsRepository::getName(const QString &assetId) const { Q_ASSERT(m_assets.count(assetId) > 0); return m_assets.at(assetId).name; } template QString AbstractAssetsRepository::getDescription(const QString &assetId) const { Q_ASSERT(m_assets.count(assetId) > 0); return m_assets.at(assetId).description; } template bool AbstractAssetsRepository::parseInfoFromXml(const QDomElement ¤tAsset, Info &res) const { QString tag = currentAsset.attribute(QStringLiteral("tag"), QString()); QString id = currentAsset.attribute(QStringLiteral("id"), QString()); if (id.isEmpty()) { id = tag; } if (!exists(tag)) { qDebug() << "++++++ Unknown asset : " << tag; return false; } // Check if there is a maximal version set if (currentAsset.hasAttribute(QStringLiteral("version"))) { // a specific version of the filter is required if (m_assets.at(tag).version < (int)(100 * currentAsset.attribute(QStringLiteral("version")).toDouble())) { return false; } } res = m_assets.at(tag); res.id = id; res.mltId = tag; // Update description if the xml provide one QString description = Xml::getSubTagContent(currentAsset, QStringLiteral("description")); if (!description.isEmpty()) { res.description = description; res.description.append(QString(" (%1)").arg(tag)); } // Update name if the xml provide one QString name = Xml::getSubTagContent(currentAsset, QStringLiteral("name")); if (!name.isEmpty()) { res.name = name; } return true; } template QDomElement AbstractAssetsRepository::getXml(const QString &assetId) const { if (m_assets.count(assetId) == 0) { qDebug() << "Error : Requesting info on unknown transition " << assetId; return QDomElement(); } return m_assets.at(assetId).xml.cloneNode().toElement(); }