generators.cpp 7.62 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/***************************************************************************
 *   Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@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) any later version.                                   *
 *                                                                         *
 *   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, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

#include "generators.h"
21
#include "assets/abstractassetsrepository.hpp"
22
#include "doc/kthumb.h"
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
23
#include "timecodedisplay.h"
24
#include "effects/effectsrepository.hpp"
25 26 27
#include "kdenlivesettings.h"

#include <QDialogButtonBox>
Nicolas Carion's avatar
Nicolas Carion committed
28 29
#include <QDir>
#include <QDomDocument>
30
#include <QFileDialog>
Nicolas Carion's avatar
Nicolas Carion committed
31 32 33
#include <QLabel>
#include <QStandardPaths>
#include <QVBoxLayout>
34

35
#include "core.h"
36
#include "klocalizedstring.h"
Nicolas Carion's avatar
Nicolas Carion committed
37
#include "kxmlgui_version.h"
38
#include "profiles/profilemodel.hpp"
Nicolas Carion's avatar
Nicolas Carion committed
39 40
#include <KMessageBox>
#include <KRecentDirs>
Nicolas Carion's avatar
Nicolas Carion committed
41
#include <memory>
42 43 44 45 46
#include <mlt++/MltConsumer.h>
#include <mlt++/MltProducer.h>
#include <mlt++/MltProfile.h>
#include <mlt++/MltTractor.h>

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
47
Generators::Generators(const QString &path, QWidget *parent)
48 49 50 51 52
    : QDialog(parent)
    , m_producer(nullptr)
    , m_timePos(nullptr)
    , m_container(nullptr)
    , m_preview(nullptr)
53 54 55 56 57 58 59 60
{
    QFile file(path);
    QDomDocument doc;
    doc.setContent(&file, false);
    file.close();
    QDomElement base = doc.documentElement();
    if (base.tagName() == QLatin1String("generator")) {
        QString generatorTag = base.attribute(QStringLiteral("tag"));
61
        setWindowTitle(i18n(base.firstChildElement(QStringLiteral("name")).text().toUtf8().data()));
Nicolas Carion's avatar
Nicolas Carion committed
62
        auto *lay = new QVBoxLayout(this);
63 64 65
        m_preview = new QLabel;
        m_preview->setMinimumSize(1, 1);
        lay->addWidget(m_preview);
66 67
        m_producer = new Mlt::Producer(pCore->getCurrentProfile()->profile(), generatorTag.toUtf8().constData());
        m_pixmap = QPixmap::fromImage(KThumb::getFrame(m_producer, 0, pCore->getCurrentProfile()->width(), pCore->getCurrentProfile()->height()));
68
        m_preview->setPixmap(m_pixmap.scaledToWidth(m_preview->width()));
Nicolas Carion's avatar
Nicolas Carion committed
69
        auto *hlay = new QHBoxLayout;
70
        hlay->addWidget(new QLabel(i18n("Duration")));
71
        m_timePos = new TimecodeDisplay(pCore->timecode(), this);
72
        if (base.hasAttribute(QStringLiteral("updateonduration"))) {
Laurent Montel's avatar
Laurent Montel committed
73
            connect(m_timePos, &TimecodeDisplay::timeCodeEditingFinished, this, &Generators::updateDuration);
74 75 76 77 78
        }
        hlay->addWidget(m_timePos);
        lay->addLayout(hlay);
        QWidget *frameWidget = new QWidget;
        lay->addWidget(frameWidget);
79 80 81 82 83 84

        m_view = new AssetParameterView(frameWidget);
        lay->addWidget(m_view);
        QString tag = base.attribute(QStringLiteral("tag"), QString());
        QString id = base.hasAttribute(QStringLiteral("id")) ? base.attribute(QStringLiteral("id")) : tag;

85
        auto prop = std::make_unique<Mlt::Properties>(m_producer->get_properties());
Nicolas Carion's avatar
Nicolas Carion committed
86
        m_assetModel.reset(new AssetParameterModel(std::move(prop), base, tag, {ObjectType::NoItem, -1})); // NOLINT
87 88
        m_view->setModel(m_assetModel, QSize(1920, 1080), false);
        connect(m_assetModel.get(), &AssetParameterModel::modelChanged, [this]() { updateProducer(); });
89

90
        lay->addStretch(10);
91
        QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
Laurent Montel's avatar
Laurent Montel committed
92 93
        connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
        connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
94 95 96 97 98
        lay->addWidget(buttonBox);
        m_timePos->setValue(KdenliveSettings::color_duration());
    }
}

99
void Generators::updateProducer()
100 101 102 103 104 105 106
{
    int w = m_pixmap.width();
    int h = m_pixmap.height();
    m_pixmap = QPixmap::fromImage(KThumb::getFrame(m_producer, 0, w, h));
    m_preview->setPixmap(m_pixmap.scaledToWidth(m_preview->width()));
}

107
void Generators::resizeEvent(QResizeEvent *event)
108 109 110 111 112 113 114 115 116 117
{
    QDialog::resizeEvent(event);
    m_preview->setPixmap(m_pixmap.scaledToWidth(m_preview->width()));
}

Generators::~Generators()
{
    delete m_timePos;
}

Nicolas Carion's avatar
Nicolas Carion committed
118
// static
Laurent Montel's avatar
Laurent Montel committed
119
void Generators::getGenerators(const QStringList &producers, QMenu *menu)
120
{
Nicolas Carion's avatar
Nicolas Carion committed
121 122
    const QStringList generatorFolders =
        QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("generators"), QStandardPaths::LocateDirectory);
123 124
    const QStringList filters = QStringList() << QStringLiteral("*.xml");
    for (const QString &folder : generatorFolders) {
125
        QDir directory(folder);
126 127
        const QStringList filesnames = directory.entryList(filters, QDir::Files);
        for (const QString &fname : filesnames) {
Nicolas Carion's avatar
Nicolas Carion committed
128
            QPair<QString, QString> result = parseGenerator(directory.absoluteFilePath(fname), producers);
129
            if (!result.first.isEmpty()) {
130
                QAction *action = menu->addAction(i18n(result.first.toUtf8().data()));
131 132 133 134 135 136
                action->setData(result.second);
            }
        }
    }
}

Nicolas Carion's avatar
Nicolas Carion committed
137 138
// static
QPair<QString, QString> Generators::parseGenerator(const QString &path, const QStringList &producers)
139
{
Nicolas Carion's avatar
Nicolas Carion committed
140
    QPair<QString, QString> result;
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
    QDomDocument doc;
    QFile file(path);
    doc.setContent(&file, false);
    file.close();
    QDomElement base = doc.documentElement();
    if (base.tagName() == QLatin1String("generator")) {
        QString generatorTag = base.attribute(QStringLiteral("tag"));
        if (producers.contains(generatorTag)) {
            result.first = base.firstChildElement(QStringLiteral("name")).text();
            result.second = path;
        }
    }
    return result;
}

void Generators::updateDuration(int duration)
{
    m_producer->set("length", duration);
    m_producer->set_in_and_out(0, duration - 1);
    updateProducer();
}

QUrl Generators::getSavedClip(QString clipFolder)
{
    if (clipFolder.isEmpty()) {
        clipFolder = KRecentDirs::dir(QStringLiteral(":KdenliveClipFolder"));
    }
    if (clipFolder.isEmpty()) {
        clipFolder = QDir::homePath();
    }
171 172 173 174 175 176 177 178 179
    QFileDialog fd(this);
    fd.setDirectory(clipFolder);
    fd.setNameFilter(i18n("MLT playlist (*.mlt)"));
    fd.setAcceptMode(QFileDialog::AcceptSave);
    fd.setFileMode(QFileDialog::AnyFile);
    fd.setDefaultSuffix(QStringLiteral("mlt"));
    if (fd.exec() != QDialog::Accepted || fd.selectedUrls().isEmpty()) {
        return QUrl();
    }
Laurent Montel's avatar
Laurent Montel committed
180
    QUrl url = fd.selectedUrls().constFirst();
181

182
    if (url.isValid()) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
183
        Mlt::Tractor trac(*m_producer->profile());
184 185
        m_producer->set("length", m_timePos->getValue());
        m_producer->set_in_and_out(0, m_timePos->getValue() - 1);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
186
        trac.set_track(*m_producer, 0);
187
        Mlt::Consumer c(*m_producer->profile(), "xml", url.toLocalFile().toUtf8().constData());
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
188
        c.connect(trac);
189 190 191 192
        c.run();
        return url;
    }
    return QUrl();
Vincent Pinon's avatar
Vincent Pinon committed
193
}