Allow saving the full effect stack as an effect - kind of restores effect groups.

Related to #4
parent a61fcd9b
Pipeline #15950 passed with stage
in 17 minutes
......@@ -306,7 +306,6 @@ template <typename AssetType> QString AbstractAssetsRepository<AssetType>::getDe
template <typename AssetType> bool AbstractAssetsRepository<AssetType>::parseInfoFromXml(const QDomElement &currentAsset, Info &res) const
{
QString tag = currentAsset.attribute(QStringLiteral("tag"), QString());
QString id = currentAsset.attribute(QStringLiteral("id"), QString());
if (id.isEmpty()) {
id = tag;
......
......@@ -115,9 +115,18 @@ void EffectTreeModel::reloadEffect(const QString &path)
if (asset.first.isEmpty() || m_customCategory == nullptr) {
return;
}
// Check if item already existed, and remove
for (int i = 0; i < m_customCategory->childCount(); i++) {
std::shared_ptr<TreeItem> item = m_customCategory->child(i);
if (item->dataColumn(idCol).toString() == asset.first) {
m_customCategory->removeChild(item);
break;
}
}
bool isFav = KdenliveSettings::favorite_effects().contains(asset.first);
QList<QVariant> data {asset.first, asset.first, QVariant::fromValue(EffectType::Custom), isFav};
m_customCategory->appendChild(data);
}
void EffectTreeModel::reloadAssetMenu(QMenu *effectsMenu, KActionCategory *effectActions)
......
......@@ -87,6 +87,7 @@ QString EffectListWidget::getMimeType(const QString &assetId) const
void EffectListWidget::reloadCustomEffect(const QString &path)
{
static_cast<EffectTreeModel *>(m_model.get())->reloadEffect(path);
m_proxyModel->sort(0, Qt::AscendingOrder);
}
void EffectListWidget::reloadEffectMenu(QMenu *effectsMenu, KActionCategory *effectActions)
......
......@@ -75,8 +75,40 @@ void EffectsRepository::parseCustomAssetFile(const QString &file_name, std::unor
QDomElement base = doc.documentElement();
if (base.tagName() == QLatin1String("effectgroup")) {
QDomNodeList effects = base.elementsByTagName(QStringLiteral("effect"));
if (effects.count() != 1) {
qDebug() << "Error: found unsupported effect group" << base.attribute(QStringLiteral("name"))<<" : "<<file_name;
if (effects.count() > 1) {
// Effect group
//qDebug() << "Error: found unsupported effect group" << base.attribute(QStringLiteral("name"))<<" : "<<file_name;
Info result;
result.xml = base;
for (int i = 0; i < effects.count(); ++i) {
QDomNode currentNode = effects.item(i);
if (currentNode.isNull()) {
continue;
}
QDomElement currentEffect = currentNode.toElement();
QString currentId = currentEffect.attribute(QStringLiteral("id"), QString());
if (currentId.isEmpty()) {
currentId = currentEffect.attribute(QStringLiteral("tag"), QString());
}
if (!exists(currentId)) {
qDebug() << "Error: found unsupported effect in group" << currentId<<" : "<<file_name;
return;
}
}
QString type = base.attribute(QStringLiteral("type"), QString());
if (type == QLatin1String("customAudio")) {
result.type = EffectType::CustomAudio;
} else {
result.type = EffectType::Custom;
}
result.id = base.attribute(QStringLiteral("id"), QString());
if (result.id.isEmpty()) {
result.id = QFileInfo(file_name).baseName();
}
if (!result.id.isEmpty()) {
result.name = result.id;
customAssets[result.id] = result;
}
return;
}
}
......@@ -214,6 +246,17 @@ QPair<QString, QString> EffectsRepository::reloadCustom(const QString &path)
return result;
}
bool EffectsRepository::isGroup(const QString &assetId) const
{
if (m_assets.count(assetId) > 0) {
QDomElement xml = m_assets.at(assetId).xml;
if (xml.tagName() == QLatin1String("effectgroup")) {
return true;
}
}
return false;
}
QPair <QStringList, QStringList> EffectsRepository::fixDeprecatedEffects()
{
......
......@@ -55,6 +55,8 @@ public:
/* @brief Check custom effects (older custom effects need an update to default and current values
* returns a list of effects that were incorrectly converted */
QPair<QStringList, QStringList> fixDeprecatedEffects();
/** @brief Returns true if this is an effect group */
bool isGroup(const QString &assetId) const;
protected:
// Constructor is protected because class is a Singleton
......
......@@ -420,6 +420,10 @@ bool EffectStackModel::appendEffect(const QString &effectId, bool makeCurrent)
QWriteLocker locker(&m_lock);
std::unordered_set<int> previousFadeIn = m_fadeIns;
std::unordered_set<int> previousFadeOut = m_fadeOuts;
if (EffectsRepository::get()->isGroup(effectId)) {
QDomElement doc = EffectsRepository::get()->getXml(effectId);
return copyXmlEffect(doc);
}
auto effect = EffectItemModel::construct(effectId, shared_from_this());
PlaylistState::ClipState state = pCore->getItemState(m_ownerId);
if (effect->isAudio()) {
......
......@@ -108,6 +108,7 @@ CollapsibleEffectView::CollapsibleEffectView(const std::shared_ptr<EffectItemMod
m_colorIcon = new QLabel(this);
l->insertWidget(0, m_colorIcon);
m_colorIcon->setFixedSize(collapseButton->sizeHint());
m_colorIcon->setToolTip(effectName);
title = new KSqueezedTextLabel(this);
l->insertWidget(2, title);
......@@ -180,6 +181,7 @@ CollapsibleEffectView::CollapsibleEffectView(const std::shared_ptr<EffectItemMod
m_view->setVisible(false);
}
m_menu->addAction(QIcon::fromTheme(QStringLiteral("document-save")), i18n("Save Effect"), this, SLOT(slotSaveEffect()));
m_menu->addAction(QIcon::fromTheme(QStringLiteral("document-save-all")), i18n("Save Effect Stack"), this, SIGNAL(saveStack()));
if (!m_regionEffect) {
/*if (m_info.groupIndex == -1) {
m_menu->addAction(m_groupAction);
......@@ -478,7 +480,6 @@ void CollapsibleEffectView::slotSaveEffect()
QDomElement effectprops = effect.firstChildElement(QStringLiteral("properties"));
effectprops.setAttribute(QStringLiteral("id"), name);
effectprops.setAttribute(QStringLiteral("type"), QStringLiteral("custom"));
QFile file(dir.absoluteFilePath(name + QStringLiteral(".xml")));
if (file.open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream out(&file);
......@@ -488,6 +489,36 @@ void CollapsibleEffectView::slotSaveEffect()
emit reloadEffect(dir.absoluteFilePath(name + QStringLiteral(".xml")));
}
QDomDocument CollapsibleEffectView::toXml() const
{
QDomDocument doc;
// Get base effect xml
QString effectId = m_model->getAssetId();
// Adjust param values
QVector<QPair<QString, QVariant>> currentValues = m_model->getAllParameters();
QMap<QString, QString> values;
QDomElement effect = doc.createElement(QStringLiteral("effect"));
doc.appendChild(effect);
effect.setAttribute(QStringLiteral("id"), effectId);
QLocale locale;
locale.setNumberOptions(QLocale::OmitGroupSeparator);
for (const auto &param : currentValues) {
QDomElement xmlParam = doc.createElement(QStringLiteral("property"));
effect.appendChild(xmlParam);
xmlParam.setAttribute(QStringLiteral("name"), param.first);
QString value;
if (param.second.type() == QVariant::Double) {
value = locale.toString(param.second.toDouble());
} else {
value = param.second.toString();
}
QDomText val = doc.createTextNode(value);
xmlParam.appendChild(val);
}
return doc;
}
void CollapsibleEffectView::slotResetEffect()
{
m_view->resetValues();
......
......@@ -82,6 +82,8 @@ public:
void setActiveKeyframe(int kf);
/** @brief Returns true if effect can be moved (false for speed effect). */
bool isMovable() const;
/** @brief Returns the effect in xml format for saving. */
QDomDocument toXml() const;
public slots:
void slotSyncEffectsPos(int pos);
......@@ -165,6 +167,8 @@ signals:
void startDrag(QPixmap, std::shared_ptr<EffectItemModel> effectModel);
void activateEffect(std::shared_ptr<EffectItemModel> effectModel);
void refresh();
/** @brief Requests saving the full effect stack. */
void saveStack();
};
#endif
......@@ -39,7 +39,12 @@
#include <QScrollBar>
#include <QTreeView>
#include <QVBoxLayout>
#include <QInputDialog>
#include <QDir>
#include <KMessageBox>
#include <utility>
WidgetDelegate::WidgetDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
......@@ -230,6 +235,7 @@ void EffectStackView::loadEffects()
connect(view, &CollapsibleEffectView::reloadEffect, this, &EffectStackView::reloadEffect);
connect(view, &CollapsibleEffectView::switchHeight, this, &EffectStackView::slotAdjustDelegate, Qt::DirectConnection);
connect(view, &CollapsibleEffectView::startDrag, this, &EffectStackView::slotStartDrag);
connect(view, &CollapsibleEffectView::saveStack, this, &EffectStackView::slotSaveStack);
connect(view, &CollapsibleEffectView::createGroup, m_model.get(), &EffectStackModel::slotCreateGroup);
connect(view, &CollapsibleEffectView::activateEffect, this, &EffectStackView::slotActivateEffect);
connect(this, &EffectStackView::blockWheenEvent, view, &CollapsibleEffectView::blockWheenEvent);
......@@ -433,6 +439,43 @@ void EffectStackView::doActivateEffect(int row, QModelIndex activeIx, bool force
}
}
void EffectStackView::slotSaveStack()
{
QString name = QInputDialog::getText(this, i18n("Save Effect Stack"), i18n("Name for saved stack: "));
if (name.trimmed().isEmpty()) {
return;
}
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/effects/"));
if (!dir.exists()) {
dir.mkpath(QStringLiteral("."));
}
if (dir.exists(name + QStringLiteral(".xml"))) {
if (KMessageBox::questionYesNo(this, i18n("File %1 already exists.\nDo you want to overwrite it?", name + QStringLiteral(".xml"))) == KMessageBox::No) {
return;
}
}
QDomDocument doc;
QDomElement effect = doc.createElement(QStringLiteral("effectgroup"));
effect.setAttribute(QStringLiteral("id"), name);
effect.setAttribute(QStringLiteral("parentIn"), pCore->getItemIn(m_model->getOwnerId()));
doc.appendChild(effect);
for (int i = 0; i <= m_model->rowCount(); ++i) {
CollapsibleEffectView *w = static_cast<CollapsibleEffectView *>(m_effectsTree->indexWidget(m_model->index(i, 0, QModelIndex())));
if (w) {
effect.appendChild(doc.importNode(w->toXml().documentElement(), true));
}
}
QFile file(dir.absoluteFilePath(name + QStringLiteral(".xml")));
if (file.open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream out(&file);
out << doc.toString();
}
file.close();
reloadEffect(dir.absoluteFilePath(name + QStringLiteral(".xml")));
}
/*
void EffectStackView::switchBuiltStack(bool show)
{
......
......@@ -105,6 +105,9 @@ private slots:
void loadEffects();
void updateTreeHeight();
void doActivateEffect(int row, QModelIndex ix, bool force = false);
/** @brief Save current effect stack
*/
void slotSaveStack();
// void switchBuiltStack(bool show);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment