Various cleanup and fixes for assetlist

parent 13b88a82
Pipeline #16064 passed with stage
in 17 minutes and 30 seconds
......@@ -90,8 +90,7 @@ template <typename AssetType> void AbstractAssetsRepository<AssetType>::init()
QListIterator<QString> 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 filter {QStringLiteral("*.xml")};
QStringList fileList = current_dir.entryList(filter, QDir::Files);
for (const auto &file : fileList) {
QString path = current_dir.absoluteFilePath(file);
......
......@@ -41,6 +41,7 @@ QHash<int, QByteArray> AssetTreeModel::roleNames() const
roles[IdRole] = "identifier";
roles[NameRole] = "name";
roles[FavoriteRole] = "favorite";
roles[TypeRole] = "type";
return roles;
}
......@@ -99,6 +100,8 @@ QVariant AssetTreeModel::data(const QModelIndex &index, int role) const
return item->dataColumn(AssetTreeModel::idCol);
case FavoriteRole:
return item->dataColumn(AssetTreeModel::favCol);
case TypeRole:
return item->dataColumn(AssetTreeModel::typeCol);
case NameRole:
case Qt::DisplayRole:
return item->dataColumn(index.column());
......
......@@ -36,7 +36,7 @@ class AssetTreeModel : public AbstractTreeModel
public:
explicit AssetTreeModel(QObject *parent = nullptr);
enum { IdRole = Qt::UserRole + 1, NameRole, FavoriteRole };
enum { IdRole = Qt::UserRole + 1, NameRole, FavoriteRole, TypeRole };
// Helper function to retrieve name
QString getName(const QModelIndex &index) const;
......@@ -48,6 +48,7 @@ public:
QVariant data(const QModelIndex &index, int role) const override;
virtual void reloadAssetMenu(QMenu *effectsMenu, KActionCategory *effectActions) = 0;
virtual void setFavorite(const QModelIndex &index, bool favorite, bool isEffect) = 0;
virtual void deleteEffect(const QModelIndex &index) = 0;
// for convenience, we store the column of each data field
static int nameCol, idCol, favCol, typeCol, preferredCol;
......
......@@ -74,6 +74,11 @@ void AssetListWidget::setFavorite(const QModelIndex &index, bool favorite, bool
m_model->setFavorite(m_proxyModel->mapToSource(index), favorite, isEffect);
}
void AssetListWidget::deleteCustomEffect(const QModelIndex &index)
{
m_model->deleteEffect(m_proxyModel->mapToSource(index));
}
QString AssetListWidget::getDescription(bool isEffect, const QModelIndex &index) const
{
return m_model->getDescription(isEffect, m_proxyModel->mapToSource(index));
......
......@@ -52,6 +52,9 @@ public:
/* @brief Sets whether this effect belongs to favorites */
void setFavorite(const QModelIndex &index, bool favorite = true, bool isEffect = true);
/* @brief Delete a custom effect */
void deleteCustomEffect(const QModelIndex &index);
/* @brief Returns the description of the asset given its model index */
QString getDescription(bool isEffect, const QModelIndex &index) const;
......@@ -68,7 +71,7 @@ public:
/* @brief Rebuild the view by resetting the source. Is there a better way? */
void reset();
protected:
void setup();
std::shared_ptr<AssetTreeModel> m_model;
......
......@@ -25,6 +25,7 @@ import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Window 2.2
import QtQml.Models 2.11
import com.enums 1.0
Rectangle {
id: listRoot
......@@ -256,9 +257,10 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
visible: assetDelegate.isItem
property bool isFavorite: model == undefined || model.favorite === undefined ? false : model.favorite
property bool isCustom: model == undefined ? false : model.type == AssetType.Custom || model.type == AssetType.CustomAudio
height: parent.height * 0.8
width: height
source: 'image://asseticon/' + styleData.value
source: assetText.text == '' ? '' : 'image://asseticon/' + assetText.text + '/' + model.type
}
Label {
id: assetText
......@@ -287,6 +289,7 @@ Rectangle {
} else {
drag.target = undefined
assetContextMenu.isItemFavorite = assetThumb.isFavorite
assetContextMenu.isCustom = assetThumb.isCustom
assetContextMenu.popup()
mouse.accepted = false
}
......@@ -311,20 +314,20 @@ Rectangle {
Menu {
id: assetContextMenu
property bool isItemFavorite
property bool isDisplayed: false
property bool isCustom: false
MenuItem {
id: favMenu
text: assetContextMenu.isItemFavorite ? i18n("Remove from favorites") : i18n("Add to favorites")
property url thumbSource
onTriggered: {
assetlist.setFavorite(sel.currentIndex, !assetContextMenu.isItemFavorite)
}
}
onAboutToShow: {
isDisplayed = true;
}
onAboutToHide: {
isDisplayed = false;
MenuItem {
id: removeMenu
text: i18n("Delete custom effect")
visible: isEffectList && assetContextMenu.isCustom
onTriggered: {
assetlist.deleteCustomEffect(sel.currentIndex)
}
}
}
......
......@@ -33,34 +33,23 @@ AssetIconProvider::AssetIconProvider(bool effect)
m_effect = effect;
}
QImage AssetIconProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
QImage AssetIconProvider::requestImage(const QString &name, QSize *size, const QSize &requestedSize)
{
QImage result;
if (id == QStringLiteral("root") || id.isEmpty()) {
if (name.isEmpty()) {
QPixmap pix(30, 30);
return pix.toImage();
}
if (m_effect && EffectsRepository::get()->exists(id)) {
QString name = EffectsRepository::get()->getName(id);
result = makeIcon(id, name, requestedSize);
if (size) {
*size = result.size();
}
} else if (!m_effect && TransitionsRepository::get()->exists(id)) {
QString name = TransitionsRepository::get()->getName(id);
result = makeIcon(id, name, requestedSize);
if (size) {
*size = result.size();
}
} else {
qDebug() << "Asset not found " << id;
result = makeIcon(name, requestedSize);
if (size) {
*size = result.size();
}
return result;
}
QImage AssetIconProvider::makeIcon(const QString &effectId, const QString &effectName, const QSize &size)
QImage AssetIconProvider::makeIcon(const QString &effectName, const QSize &size)
{
Q_UNUSED(size);
QPixmap pix(30, 30);
......@@ -76,16 +65,15 @@ QImage AssetIconProvider::makeIcon(const QString &effectId, const QString &effec
bool isAudio = false;
bool isCustom = false;
bool isGroup = false;
AssetListType::AssetType type = (AssetListType::AssetType)effectName.section(QLatin1Char('/'), -1).toInt();
if (m_effect) {
EffectType type = EffectsRepository::get()->getType(effectId);
isAudio = type == EffectType::Audio || type == EffectType::CustomAudio;
isCustom = type == EffectType::CustomAudio || type == EffectType::Custom;
isAudio = type == AssetListType::AssetType::Audio || type == AssetListType::AssetType::CustomAudio;
isCustom = type == AssetListType::AssetType::CustomAudio || type == AssetListType::AssetType::Custom;
if (isCustom) {
isGroup = EffectsRepository::get()->isGroup(effectId);
//isGroup = EffectsRepository::get()->isGroup(effectId);
}
} else {
auto type = TransitionsRepository::get()->getType(effectId);
isAudio = (type == TransitionType::AudioComposition) || (type == TransitionType::AudioTransition);
isAudio = (type == AssetListType::AssetType::AudioComposition) || (type == AssetListType::AssetType::AudioTransition);
}
QPainter p;
if (isCustom) {
......
......@@ -31,10 +31,10 @@ class AssetIconProvider : public QQuickImageProvider
{
public:
explicit AssetIconProvider(bool effect);
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
QImage requestImage(const QString &name, QSize *size, const QSize &requestedSize) override;
private:
QImage makeIcon(const QString &effectId, const QString &effectName, const QSize &size);
QImage makeIcon(const QString &effectName, const QSize &size);
std::unique_ptr<KImageCache> m_cache;
bool m_effect;
......
......@@ -90,6 +90,12 @@ namespace TimelineMode {
enum EditMode { NormalEdit = 0, OverwriteEdit = 1, InsertEdit = 2 };
}
namespace AssetListType {
Q_NAMESPACE
enum AssetType { Preferred, Video, Audio, Custom, CustomAudio, Favorites, AudioComposition, VideoShortComposition, VideoComposition, AudioTransition, VideoTransition, Hidden = -1 };
Q_ENUM_NS(AssetType)
}
namespace ClipType {
Q_NAMESPACE
enum ProducerType {
......
......@@ -30,7 +30,7 @@ EffectFilter::EffectFilter(QObject *parent)
m_type_enabled = false;
}
void EffectFilter::setFilterType(bool enabled, EffectType type)
void EffectFilter::setFilterType(bool enabled, AssetListType::AssetType type)
{
m_type_enabled = enabled;
m_type_value = type;
......@@ -39,28 +39,28 @@ void EffectFilter::setFilterType(bool enabled, EffectType type)
void EffectFilter::reloadFilterOnFavorite()
{
if (m_type_enabled && m_type_value == EffectType::Favorites) {
if (m_type_enabled && m_type_value == AssetListType::AssetType::Favorites) {
invalidateFilter();
}
}
bool EffectFilter::filterType(const std::shared_ptr<TreeItem> &item) const
{
auto itemType = item->dataColumn(AssetTreeModel::typeCol).value<EffectType>();
if (itemType == EffectType::Hidden) {
auto itemType = item->dataColumn(AssetTreeModel::typeCol).value<AssetListType::AssetType>();
if (itemType == AssetListType::AssetType::Hidden) {
return false;
}
if (!m_type_enabled) {
return true;
}
if (m_type_value == EffectType::Favorites) {
if (m_type_value == AssetListType::AssetType::Favorites) {
return item->dataColumn(AssetTreeModel::favCol).toBool();
}
if (m_type_value == EffectType::Preferred) {
if (m_type_value == AssetListType::AssetType::Preferred) {
return item->dataColumn(AssetTreeModel::preferredCol).toBool();
}
if (m_type_value == EffectType::Custom) {
return itemType == m_type_value || itemType == EffectType::CustomAudio;
if (m_type_value == AssetListType::AssetType::Custom) {
return itemType == m_type_value || itemType == AssetListType::AssetType::CustomAudio;
}
return itemType == m_type_value;
}
......@@ -68,7 +68,7 @@ bool EffectFilter::filterType(const std::shared_ptr<TreeItem> &item) const
bool EffectFilter::applyAll(std::shared_ptr<TreeItem> item) const
{
if (!m_name_value.isEmpty()) {
if (m_type_value == EffectType::Preferred) {
if (m_type_value == AssetListType::AssetType::Preferred) {
return filterName(item);
}
return filterType(item) && filterName(item);
......
......@@ -40,7 +40,7 @@ public:
@param enabled whether to enable this filter
@param type Effect type to display
*/
void setFilterType(bool enabled, EffectType type);
void setFilterType(bool enabled, AssetListType::AssetType type);
void reloadFilterOnFavorite() override;
protected:
......@@ -48,6 +48,6 @@ protected:
bool applyAll(std::shared_ptr<TreeItem> item) const override;
bool m_type_enabled;
EffectType m_type_value;
AssetListType::AssetType m_type_value;
};
#endif
......@@ -85,14 +85,14 @@ std::shared_ptr<EffectTreeModel> EffectTreeModel::construct(const QString &categ
QString favCategory = QStringLiteral("kdenlive:favorites");
for (const auto &effect : allEffects) {
auto targetCategory = miscCategory;
EffectType type = EffectsRepository::get()->getType(effect.first);
AssetListType::AssetType type = EffectsRepository::get()->getType(effect.first);
if (effectCategory.contains(effect.first)) {
targetCategory = effectCategory[effect.first];
} else if (type == EffectType::Audio) {
} else if (type == AssetListType::AssetType::Audio) {
targetCategory = audioCategory;
}
if (type == EffectType::Custom || type == EffectType::CustomAudio) {
if (type == AssetListType::AssetType::Custom || type == AssetListType::AssetType::CustomAudio) {
targetCategory = self->m_customCategory;
}
......@@ -124,9 +124,19 @@ void EffectTreeModel::reloadEffect(const QString &path)
}
}
bool isFav = KdenliveSettings::favorite_effects().contains(asset.first);
QList<QVariant> data {asset.first, asset.first, QVariant::fromValue(EffectType::Custom), isFav};
QList<QVariant> data {asset.first, asset.first, QVariant::fromValue(AssetListType::AssetType::Custom), isFav};
m_customCategory->appendChild(data);
}
void EffectTreeModel::deleteEffect(const QModelIndex &index)
{
if (!index.isValid()) {
return;
}
std::shared_ptr<TreeItem> item = getItemById((int)index.internalId());
const QString id = item->dataColumn(idCol).toString();
m_customCategory->removeChild(item);
EffectsRepository::get()->deleteEffect(id);
}
void EffectTreeModel::reloadAssetMenu(QMenu *effectsMenu, KActionCategory *effectActions)
......@@ -171,3 +181,4 @@ void EffectTreeModel::setFavorite(const QModelIndex &index, bool favorite, bool
}
KdenliveSettings::setFavorite_effects(favs);
}
......@@ -40,6 +40,8 @@ public:
void reloadEffect(const QString &path);
void reloadAssetMenu(QMenu *effectsMenu, KActionCategory *effectActions) override;
void setFavorite(const QModelIndex &index, bool favorite, bool isEffect) override;
void deleteEffect(const QModelIndex &index) override;
protected:
std::shared_ptr<TreeItem> m_customCategory;
};
......
......@@ -66,15 +66,15 @@ EffectListWidget::~EffectListWidget()
void EffectListWidget::setFilterType(const QString &type)
{
if (type == "video") {
static_cast<EffectFilter *>(m_proxyModel.get())->setFilterType(true, EffectType::Video);
static_cast<EffectFilter *>(m_proxyModel.get())->setFilterType(true, AssetListType::AssetType::Video);
} else if (type == "audio") {
static_cast<EffectFilter *>(m_proxyModel.get())->setFilterType(true, EffectType::Audio);
static_cast<EffectFilter *>(m_proxyModel.get())->setFilterType(true, AssetListType::AssetType::Audio);
} else if (type == "custom") {
static_cast<EffectFilter *>(m_proxyModel.get())->setFilterType(true, EffectType::Custom);
static_cast<EffectFilter *>(m_proxyModel.get())->setFilterType(true, AssetListType::AssetType::Custom);
} else if (type == "favorites") {
static_cast<EffectFilter *>(m_proxyModel.get())->setFilterType(true, EffectType::Favorites);
static_cast<EffectFilter *>(m_proxyModel.get())->setFilterType(true, AssetListType::AssetType::Favorites);
} else {
static_cast<EffectFilter *>(m_proxyModel.get())->setFilterType(true, EffectType::Preferred);
static_cast<EffectFilter *>(m_proxyModel.get())->setFilterType(true, AssetListType::AssetType::Preferred);
}
}
......
......@@ -77,6 +77,7 @@ public:
q->setFavorite(index, favorite, true);
q->updateFavorite(index);
}
Q_INVOKABLE void deleteCustomEffect(const QModelIndex &index) { q->deleteCustomEffect(index); }
Q_INVOKABLE QString getDescription(const QModelIndex &index) const { return q->getDescription(true, index); }
Q_INVOKABLE QVariantMap getMimeData(const QString &assetId) const { return q->getMimeData(assetId); }
......
......@@ -36,7 +36,7 @@ std::unique_ptr<EffectsRepository> EffectsRepository::instance;
std::once_flag EffectsRepository::m_onceFlag;
EffectsRepository::EffectsRepository()
: AbstractAssetsRepository<EffectType>()
: AbstractAssetsRepository<AssetListType::AssetType>()
{
init();
// Check that our favorite effects are valid
......@@ -90,16 +90,16 @@ void EffectsRepository::parseCustomAssetFile(const QString &file_name, std::unor
if (currentId.isEmpty()) {
currentId = currentEffect.attribute(QStringLiteral("tag"), QString());
}
if (!exists(currentId)) {
if (!exists(currentId) && customAssets.count(currentId) == 0) {
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;
result.type = AssetListType::AssetType::CustomAudio;
} else {
result.type = EffectType::Custom;
result.type = AssetListType::AssetType::Custom;
}
result.id = base.attribute(QStringLiteral("id"), QString());
if (result.id.isEmpty()) {
......@@ -140,16 +140,16 @@ void EffectsRepository::parseCustomAssetFile(const QString &file_name, std::unor
// Parse type information.
// Video effect by default
result.type = EffectType::Video;
result.type = AssetListType::AssetType::Video;
QString type = currentEffect.attribute(QStringLiteral("type"), QString());
if (type == QLatin1String("audio")) {
result.type = EffectType::Audio;
result.type = AssetListType::AssetType::Audio;
} else if (type == QLatin1String("customVideo")) {
result.type = EffectType::Custom;
result.type = AssetListType::AssetType::Custom;
} else if (type == QLatin1String("customAudio")) {
result.type = EffectType::CustomAudio;
result.type = AssetListType::AssetType::CustomAudio;
} else if (type == QLatin1String("hidden")) {
result.type = EffectType::Hidden;
result.type = AssetListType::AssetType::Hidden;
} else if (type == QLatin1String("custom")) {
// Old type effect, update to customVideo / customAudio
const QString effectTag = currentEffect.attribute(QStringLiteral("tag"));
......@@ -157,10 +157,10 @@ void EffectsRepository::parseCustomAssetFile(const QString &file_name, std::unor
if (metadata && metadata->is_valid()) {
Mlt::Properties tags((mlt_properties)metadata->get_data("tags"));
if (QString(tags.get(0)) == QLatin1String("Audio")) {
result.type = EffectType::CustomAudio;
result.type = AssetListType::AssetType::CustomAudio;
currentEffect.setAttribute(QStringLiteral("type"), QStringLiteral("customAudio"));
} else {
result.type = EffectType::Custom;
result.type = AssetListType::AssetType::Custom;
currentEffect.setAttribute(QStringLiteral("type"), QStringLiteral("customVideo"));
}
QFile effectFile(file_name);
......@@ -187,10 +187,10 @@ QStringList EffectsRepository::assetDirs() const
void EffectsRepository::parseType(QScopedPointer<Mlt::Properties> &metadata, Info &res)
{
res.type = EffectType::Video;
res.type = AssetListType::AssetType::Video;
Mlt::Properties tags((mlt_properties)metadata->get_data("tags"));
if (QString(tags.get(0)) == QLatin1String("Audio")) {
res.type = EffectType::Audio;
res.type = AssetListType::AssetType::Audio;
}
}
......@@ -385,3 +385,16 @@ QPair <QString, QString> EffectsRepository::fixCustomAssetFile(const QString &pa
}
return results;
}
void EffectsRepository::deleteEffect(const QString &id)
{
if (!exists(id)) {
return;
}
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/effects/"));
QFile file(dir.absoluteFilePath(id + QStringLiteral(".xml")));
if (file.exists()) {
file.remove();
m_assets.erase(id);
}
}
......@@ -33,10 +33,7 @@
* Note that this class is a Singleton
*/
enum class EffectType { Preferred, Video, Audio, Custom, CustomAudio, Favorites, Hidden = -1 };
Q_DECLARE_METATYPE(EffectType)
class EffectsRepository : public AbstractAssetsRepository<EffectType>
class EffectsRepository : public AbstractAssetsRepository<AssetListType::AssetType>
{
public:
......@@ -57,6 +54,7 @@ public:
QPair<QStringList, QStringList> fixDeprecatedEffects();
/** @brief Returns true if this is an effect group */
bool isGroup(const QString &assetId) const;
void deleteEffect(const QString &id);
protected:
// Constructor is protected because class is a Singleton
......@@ -82,7 +80,7 @@ protected:
/* @brief Returns the metadata associated with the given asset*/
Mlt::Properties *getMetadata(const QString &assetId) const override;
QPair <QString, QString> fixCustomAssetFile(const QString &path);
static std::unique_ptr<EffectsRepository> instance;
......
......@@ -103,12 +103,11 @@ void EffectItemModel::plant(const std::weak_ptr<Mlt::Service> &service)
void EffectItemModel::loadClone(const std::weak_ptr<Mlt::Service> &service)
{
if (auto ptr = service.lock()) {
const QString effectId = getAssetId();
std::shared_ptr<EffectItemModel> effect = nullptr;
for (int i = 0; i < ptr->filter_count(); i++) {
std::unique_ptr<Mlt::Filter> filt(ptr->filter(i));
QString effName = filt->get("kdenlive_id");
if (effName == effectId && filt->get_int("_kdenlive_processed") == 0) {
if (effName == m_assetId && filt->get_int("_kdenlive_processed") == 0) {
if (auto ptr2 = m_model.lock()) {
effect = EffectItemModel::construct(std::move(filt), ptr2);
int childId = ptr->get_int("_childid");
......@@ -217,6 +216,6 @@ bool EffectItemModel::isCollapsed()
bool EffectItemModel::isAudio() const
{
EffectType type = EffectsRepository::get()->getType(getAssetId());
return type == EffectType::Audio || type == EffectType::CustomAudio;
AssetListType::AssetType type = EffectsRepository::get()->getType(m_assetId);
return type == AssetListType::AssetType::Audio || type == AssetListType::AssetType::CustomAudio;
}
......@@ -283,11 +283,12 @@ bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &re
qDebug()<<"// GOT PREVIOUS PARENTIN: "<<parentIn<<"\n\n=======\n=======\n\n";
int currentIn = pCore->getItemIn(m_ownerId);
PlaylistState::ClipState state = pCore->getItemState(m_ownerId);
bool effectAdded = false;
for (int i = 0; i < nodeList.count(); ++i) {
QDomElement node = nodeList.item(i).toElement();
const QString effectId = node.attribute(QStringLiteral("id"));
EffectType type = EffectsRepository::get()->getType(effectId);
bool isAudioEffect = type == EffectType::Audio || type == EffectType::CustomAudio;
AssetListType::AssetType type = EffectsRepository::get()->getType(effectId);
bool isAudioEffect = type == AssetListType::AssetType::Audio || type == AssetListType::AssetType::CustomAudio;
if (isAudioEffect) {
if (state != PlaylistState::AudioOnly) {
continue;
......@@ -343,9 +344,10 @@ bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &re
effect->filter().set("out", filterOut);
}
local_redo();
effectAdded = true;
UPDATE_UNDO_REDO(local_redo, local_undo, undo, redo);
}
if (true) {
if (effectAdded) {
Fun update = [this]() {
emit dataChanged(QModelIndex(), QModelIndex(), {});
return true;
......@@ -354,7 +356,7 @@ bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &re
PUSH_LAMBDA(update, redo);
PUSH_LAMBDA(update, undo);
}
return true;
return effectAdded;
}
bool EffectStackModel::copyEffect(const std::shared_ptr<AbstractEffectItem> &sourceItem, PlaylistState::ClipState state)
......
......@@ -160,12 +160,12 @@ void EffectStackView::dropEvent(QDropEvent *event)
} else {
bool added = false;
if (row < m_model->rowCount()) {
if (m_model->appendEffect(effectId)) {
if (m_model->appendEffect(effectId) && m_model->rowCount() > 0) {
added = true;
m_model->moveEffect(row, m_model->getEffectStackRow(m_model->rowCount() - 1));
}
} else {
if (m_model->appendEffect(effectId)) {
if (m_model->appendEffect(effectId) && m_model->rowCount() > 0) {
added = true;
std::shared_ptr<AbstractEffectItem> item = m_model->getEffectStackRow(m_model->rowCount() - 1);
if (item) {
......@@ -442,7 +442,7 @@ 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()) {
if (name.trimmed().isEmpty() || m_model->rowCount() <= 0) {
return;
}
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/effects/"));
......@@ -459,6 +459,10 @@ void EffectStackView::slotSaveStack()
QDomDocument doc;
QDomElement effect = doc.createElement(QStringLiteral("effectgroup"));
effect.setAttribute(QStringLiteral("id"), name);
auto item = m_model->getEffectStackRow(0);
if (item->isAudio()) {
effect.setAttribute(QStringLiteral("type"), QStringLiteral("customAudio"));
}
effect.setAttribute(QStringLiteral("parentIn"), pCore->getItemIn(m_model->getOwnerId()));
doc.appendChild(effect);
for (int i = 0; i <= m_model->rowCount(); ++i) {
......
......@@ -216,7 +216,7 @@ bool AudioThumbJob::computeWithFFMPEG()