diff --git a/src/assets/view/widgets/listparamwidget.cpp b/src/assets/view/widgets/listparamwidget.cpp
index a86b57c77..9a624ec86 100644
--- a/src/assets/view/widgets/listparamwidget.cpp
+++ b/src/assets/view/widgets/listparamwidget.cpp
@@ -1,151 +1,149 @@
/***************************************************************************
* Copyright (C) 2016 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 "listparamwidget.h"
#include "assets/model/assetparametermodel.hpp"
#include "core.h"
#include "mainwindow.h"
ListParamWidget::ListParamWidget(std::shared_ptr model, QModelIndex index, QWidget *parent)
: AbstractParamWidget(std::move(model), index, parent)
{
setupUi(this);
// Get data from model
QString name = m_model->data(m_index, AssetParameterModel::NameRole).toString();
QString comment = m_model->data(m_index, AssetParameterModel::CommentRole).toString();
// setup the comment
setToolTip(comment);
m_labelComment->setText(comment);
m_widgetComment->setHidden(true);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
m_list->setIconSize(QSize(50, 30));
setMinimumHeight(m_list->sizeHint().height());
// setup the name
m_labelName->setText(m_model->data(m_index, Qt::DisplayRole).toString());
slotRefresh();
QLocale locale;
// emit the signal of the base class when appropriate
// The connection is ugly because the signal "currentIndexChanged" is overloaded in QComboBox
connect(this->m_list, static_cast(&QComboBox::currentIndexChanged),
[this](int) {
emit valueChanged(m_index, m_list->itemData(m_list->currentIndex()).toString(), true);
});
}
void ListParamWidget::setCurrentIndex(int index)
{
m_list->setCurrentIndex(index);
}
void ListParamWidget::setCurrentText(const QString &text)
{
m_list->setCurrentText(text);
}
void ListParamWidget::addItem(const QString &text, const QVariant &value)
{
m_list->addItem(text, value);
}
void ListParamWidget::setItemIcon(int index, const QIcon &icon)
{
m_list->setItemIcon(index, icon);
}
void ListParamWidget::setIconSize(const QSize &size)
{
m_list->setIconSize(size);
}
void ListParamWidget::slotShowComment(bool show)
{
if (!m_labelComment->text().isEmpty()) {
m_widgetComment->setVisible(show);
}
}
QString ListParamWidget::getValue()
{
return m_list->currentData().toString();
}
void ListParamWidget::slotRefresh()
{
const QSignalBlocker bk(m_list);
m_list->clear();
QStringList names = m_model->data(m_index, AssetParameterModel::ListNamesRole).toStringList();
QStringList values = m_model->data(m_index, AssetParameterModel::ListValuesRole).toStringList();
QString value = m_model->data(m_index, AssetParameterModel::ValueRole).toString();
if (values.first() == QLatin1String("%lumaPaths")) {
// Special case: Luma files
// Create thumbnails
if (pCore->getCurrentFrameSize().width() > 1000) {
// HD project
values = MainWindow::m_lumaFiles.value(QStringLiteral("16_9"));
} else if (pCore->getCurrentFrameSize().height() > 1000) {
values = MainWindow::m_lumaFiles.value(QStringLiteral("9_16"));
} else if (pCore->getCurrentFrameSize().height() == pCore->getCurrentFrameSize().width()) {
values = MainWindow::m_lumaFiles.value(QStringLiteral("square"));
} else if (pCore->getCurrentFrameSize().height() == 480) {
values = MainWindow::m_lumaFiles.value(QStringLiteral("NTSC"));
} else {
values = MainWindow::m_lumaFiles.value(QStringLiteral("PAL"));
}
m_list->addItem(i18n("None (Dissolve)"));
for (int j = 0; j < values.count(); ++j) {
const QString &entry = values.at(j);
m_list->addItem(values.at(j).section(QLatin1Char('/'), -1), entry);
if (!entry.isEmpty() && (entry.endsWith(QLatin1String(".png")) || entry.endsWith(QLatin1String(".pgm")))) {
- if (!MainWindow::m_lumacache.contains(entry)) {
- QImage pix(entry);
- MainWindow::m_lumacache.insert(entry, pix.scaled(50, 30, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+ if (MainWindow::m_lumacache.contains(entry)) {
+ m_list->setItemIcon(j + 1, QPixmap::fromImage(MainWindow::m_lumacache.value(entry)));
}
- m_list->setItemIcon(j + 1, QPixmap::fromImage(MainWindow::m_lumacache.value(entry)));
}
}
if (!value.isEmpty() && values.contains(value)) {
m_list->setCurrentIndex(values.indexOf(value) + 1);
}
} else {
if (names.count() != values.count()) {
names = values;
}
QLocale locale;
for (int i = 0; i < names.count(); i++) {
QString val = values.at(i);
bool ok;
double num = val.toDouble(&ok);
if (ok) {
val = locale.toString(num);
}
m_list->addItem(names.at(i), val);
}
if (!value.isEmpty()) {
int ix = m_list->findData(value);
if (ix > -1) {
m_list->setCurrentIndex(ix);
}
}
}
}
diff --git a/src/assets/view/widgets/listparamwidget.h b/src/assets/view/widgets/listparamwidget.h
index d435317d4..479a58d64 100644
--- a/src/assets/view/widgets/listparamwidget.h
+++ b/src/assets/view/widgets/listparamwidget.h
@@ -1,87 +1,88 @@
/***************************************************************************
* Copyright (C) 2016 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 . *
***************************************************************************/
#ifndef LISTPARAMETERWIDGET_H
#define LISTPARAMETERWIDGET_H
#include "assets/view/widgets/abstractparamwidget.hpp"
#include "ui_listparamwidget_ui.h"
#include
#include
class AssetParameterModel;
/** @brief This class represents a parameter that requires
the user to choose a value from a list
*/
class ListParamWidget : public AbstractParamWidget, public Ui::ListParamWidget_UI
{
Q_OBJECT
public:
/** @brief Constructor for the widgetComment
@param name String containing the name of the parameter
@param comment Optional string containing the comment associated to the parameter
@param parent Parent widget
*/
ListParamWidget(std::shared_ptr model, QModelIndex index, QWidget *parent);
/** @brief Set the index of the current displayed element
@param index Integer holding the index of the target element (0-indexed)
*/
void setCurrentIndex(int index);
/** @brief Set the text currently displayed on the list
@param text String containing the text of the element to show
*/
void setCurrentText(const QString &text);
/** @brief Add an item to the list.
@param text String to be displayed in the list
@param value Underlying value corresponding to the text
*/
void addItem(const QString &text, const QVariant &value = QVariant());
/** @brief Set the icon of a given element
@param index Integer holding the index of the target element (0-indexed)
@param icon The corresponding icon
*/
void setItemIcon(int index, const QIcon &icon);
/** @brief Set the size of the icons shown in the list
@param size Target size of the icon
*/
void setIconSize(const QSize &size);
/** @brief Returns the current value of the parameter
*/
QString getValue();
public slots:
/** @brief Toggle the comments on or off
*/
void slotShowComment(bool show) override;
/** @brief refresh the properties to reflect changes in the model
*/
void slotRefresh() override;
+
};
#endif
diff --git a/src/core.cpp b/src/core.cpp
index 072212303..89d1649f8 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -1,800 +1,813 @@
/*
Copyright (C) 2014 Till Theato
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 3 of the License, or
(at your option) any later version.
*/
#include "core.h"
#include "bin/bin.h"
#include "bin/projectitemmodel.h"
#include "capture/mediacapture.h"
#include "doc/docundostack.hpp"
#include "doc/kdenlivedoc.h"
#include "jobs/jobmanager.h"
#include "kdenlive_debug.h"
#include "kdenlivesettings.h"
#include "library/librarywidget.h"
#include "audiomixer/mixermanager.hpp"
#include "mainwindow.h"
#include "mltconnection.h"
#include "mltcontroller/clipcontroller.h"
#include "monitor/monitormanager.h"
#include "profiles/profilemodel.hpp"
#include "profiles/profilerepository.hpp"
#include "project/projectmanager.h"
#include "timeline2/model/timelineitemmodel.hpp"
#include "timeline2/view/timelinecontroller.h"
#include "timeline2/view/timelinewidget.h"
#include
#include
#include
#include
#include
#include
#ifdef Q_OS_MAC
#include
#endif
std::unique_ptr Core::m_self;
Core::Core()
: m_thumbProfile(nullptr)
, m_capture(new MediaCapture(this))
{
}
void Core::prepareShutdown()
{
m_guiConstructed = false;
QThreadPool::globalInstance()->clear();
}
Core::~Core()
{
qDebug() << "deleting core";
if (m_monitorManager) {
delete m_monitorManager;
}
// delete m_binWidget;
if (m_projectManager) {
delete m_projectManager;
}
ClipController::mediaUnavailable.reset();
}
void Core::build(bool isAppImage, const QString &MltPath)
{
if (m_self) {
return;
}
m_self.reset(new Core());
m_self->initLocale();
qRegisterMetaType("audioShortVector");
qRegisterMetaType>("QVector");
qRegisterMetaType("MessageType");
qRegisterMetaType("stringMap");
qRegisterMetaType("audioByteArray");
qRegisterMetaType>("QList");
qRegisterMetaType>("std::shared_ptr");
qRegisterMetaType>();
qRegisterMetaType("QDomElement");
qRegisterMetaType("requestClipInfo");
if (isAppImage) {
QString appPath = qApp->applicationDirPath();
KdenliveSettings::setFfmpegpath(QDir::cleanPath(appPath + QStringLiteral("/ffmpeg")));
KdenliveSettings::setFfplaypath(QDir::cleanPath(appPath + QStringLiteral("/ffplay")));
KdenliveSettings::setFfprobepath(QDir::cleanPath(appPath + QStringLiteral("/ffprobe")));
KdenliveSettings::setRendererpath(QDir::cleanPath(appPath + QStringLiteral("/melt")));
MltConnection::construct(QDir::cleanPath(appPath + QStringLiteral("/../share/mlt/profiles")));
} else {
// Open connection with Mlt
MltConnection::construct(MltPath);
}
// load the profile from disk
ProfileRepository::get()->refresh();
// load default profile
m_self->m_profile = KdenliveSettings::default_profile();
if (m_self->m_profile.isEmpty()) {
m_self->m_profile = ProjectManager::getDefaultProjectFormat();
KdenliveSettings::setDefault_profile(m_self->m_profile);
}
// Init producer shown for unavailable media
// TODO make it a more proper image, it currently causes a crash on exit
ClipController::mediaUnavailable = std::make_shared(ProfileRepository::get()->getProfile(m_self->m_profile)->profile(), "color:blue");
ClipController::mediaUnavailable->set("length", 99999999);
m_self->m_projectItemModel = ProjectItemModel::construct();
// Job manager must be created before bin to correctly connect
m_self->m_jobManager.reset(new JobManager(m_self.get()));
}
void Core::initGUI(const QUrl &Url)
{
m_guiConstructed = true;
m_profile = KdenliveSettings::default_profile();
m_currentProfile = m_profile;
profileChanged();
m_mainWindow = new MainWindow();
connect(this, &Core::showConfigDialog, m_mainWindow, &MainWindow::slotPreferences);
// load default profile and ask user to select one if not found.
if (m_profile.isEmpty()) {
m_profile = ProjectManager::getDefaultProjectFormat();
profileChanged();
KdenliveSettings::setDefault_profile(m_profile);
}
if (!ProfileRepository::get()->profileExists(m_profile)) {
KMessageBox::sorry(m_mainWindow, i18n("The default profile of Kdenlive is not set or invalid, press OK to set it to a correct value."));
// TODO this simple widget should be improved and probably use profileWidget
// we get the list of profiles
QVector> all_profiles = ProfileRepository::get()->getAllProfiles();
QStringList all_descriptions;
for (const auto &profile : all_profiles) {
all_descriptions << profile.first;
}
// ask the user
bool ok;
QString item = QInputDialog::getItem(m_mainWindow, i18n("Select Default Profile"), i18n("Profile:"), all_descriptions, 0, false, &ok);
if (ok) {
ok = false;
for (const auto &profile : all_profiles) {
if (profile.first == item) {
m_profile = profile.second;
ok = true;
}
}
}
if (!ok) {
KMessageBox::error(
m_mainWindow,
i18n("The given profile is invalid. We default to the profile \"dv_pal\", but you can change this from Kdenlive's settings panel"));
m_profile = QStringLiteral("dv_pal");
}
KdenliveSettings::setDefault_profile(m_profile);
profileChanged();
}
m_projectManager = new ProjectManager(this);
m_binWidget = new Bin(m_projectItemModel, m_mainWindow);
m_library = new LibraryWidget(m_projectManager, m_mainWindow);
m_mixerWidget = new MixerManager(m_mainWindow);
connect(m_library, SIGNAL(addProjectClips(QList)), m_binWidget, SLOT(droppedUrls(QList)));
connect(this, &Core::updateLibraryPath, m_library, &LibraryWidget::slotUpdateLibraryPath);
connect(m_capture.get(), &MediaCapture::recordStateChanged, m_mixerWidget, &MixerManager::recordStateChanged);
m_monitorManager = new MonitorManager(this);
connect(m_monitorManager, &MonitorManager::cleanMixer, m_mixerWidget, &MixerManager::clearMixers);
// Producer queue, creating MLT::Producers on request
/*
m_producerQueue = new ProducerQueue(m_binController);
connect(m_producerQueue, &ProducerQueue::gotFileProperties, m_binWidget, &Bin::slotProducerReady);
connect(m_producerQueue, &ProducerQueue::replyGetImage, m_binWidget, &Bin::slotThumbnailReady);
connect(m_producerQueue, &ProducerQueue::requestProxy,
[this](const QString &id){ m_binWidget->startJob(id, AbstractClipJob::PROXYJOB);});
connect(m_producerQueue, &ProducerQueue::removeInvalidClip, m_binWidget, &Bin::slotRemoveInvalidClip, Qt::DirectConnection);
connect(m_producerQueue, SIGNAL(addClip(QString, QMap)), m_binWidget, SLOT(slotAddUrl(QString, QMap)));
connect(m_binController.get(), SIGNAL(createThumb(QDomElement, QString, int)), m_producerQueue, SLOT(getFileProperties(QDomElement, QString, int)));
connect(m_binWidget, &Bin::producerReady, m_producerQueue, &ProducerQueue::slotProcessingDone, Qt::DirectConnection);
// TODO
connect(m_producerQueue, SIGNAL(removeInvalidProxy(QString,bool)), m_binWidget, SLOT(slotRemoveInvalidProxy(QString,bool)));*/
m_mainWindow->init();
projectManager()->init(Url, QString());
if (qApp->isSessionRestored()) {
// NOTE: we are restoring only one window, because Kdenlive only uses one MainWindow
m_mainWindow->restore(1, false);
}
QMetaObject::invokeMethod(pCore->projectManager(), "slotLoadOnOpen", Qt::QueuedConnection);
m_mainWindow->show();
QThreadPool::globalInstance()->setMaxThreadCount(qMin(4, QThreadPool::globalInstance()->maxThreadCount()));
}
+void Core::buildLumaThumbs(const QStringList &values)
+{
+ for (auto &entry : values) {
+ if (MainWindow::m_lumacache.contains(entry)) {
+ continue;
+ }
+ QImage pix(entry);
+ if (!pix.isNull()) {
+ MainWindow::m_lumacache.insert(entry, pix.scaled(50, 30, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+ }
+ }
+}
+
std::unique_ptr &Core::self()
{
if (!m_self) {
qDebug() << "Error : Core has not been created";
}
return m_self;
}
MainWindow *Core::window()
{
return m_mainWindow;
}
ProjectManager *Core::projectManager()
{
return m_projectManager;
}
MonitorManager *Core::monitorManager()
{
return m_monitorManager;
}
Monitor *Core::getMonitor(int id)
{
if (id == Kdenlive::ClipMonitor) {
return m_monitorManager->clipMonitor();
}
return m_monitorManager->projectMonitor();
}
Bin *Core::bin()
{
return m_binWidget;
}
void Core::selectBinClip(const QString &clipId, int frame, const QPoint &zone)
{
m_binWidget->selectClipById(clipId, frame, zone);
}
std::shared_ptr Core::jobManager()
{
return m_jobManager;
}
LibraryWidget *Core::library()
{
return m_library;
}
MixerManager *Core::mixer()
{
return m_mixerWidget;
}
void Core::initLocale()
{
QLocale systemLocale = QLocale();
#ifndef Q_OS_MAC
setlocale(LC_NUMERIC, nullptr);
#else
setlocale(LC_NUMERIC_MASK, nullptr);
#endif
// localeconv()->decimal_point does not give reliable results on Windows
#ifndef Q_OS_WIN
char *separator = localeconv()->decimal_point;
if (QString::fromUtf8(separator) != QChar(systemLocale.decimalPoint())) {
// qCDebug(KDENLIVE_LOG)<<"------\n!!! system locale is not similar to Qt's locale... be prepared for bugs!!!\n------";
// HACK: There is a locale conflict, so set locale to C
// Make sure to override exported values or it won't work
qputenv("LANG", "C");
#ifndef Q_OS_MAC
setlocale(LC_NUMERIC, "C");
#else
setlocale(LC_NUMERIC_MASK, "C");
#endif
systemLocale = QLocale::c();
}
#endif
systemLocale.setNumberOptions(QLocale::OmitGroupSeparator);
QLocale::setDefault(systemLocale);
}
std::unique_ptr &Core::getMltRepository()
{
return MltConnection::self()->getMltRepository();
}
std::unique_ptr &Core::getCurrentProfile() const
{
return ProfileRepository::get()->getProfile(m_currentProfile);
}
const QString &Core::getCurrentProfilePath() const
{
return m_currentProfile;
}
bool Core::setCurrentProfile(const QString &profilePath)
{
if (m_currentProfile == profilePath) {
// no change required
return true;
}
if (ProfileRepository::get()->profileExists(profilePath)) {
m_currentProfile = profilePath;
m_thumbProfile.reset();
// inform render widget
profileChanged();
m_mainWindow->updateRenderWidgetProfile();
if (m_guiConstructed && m_mainWindow->getCurrentTimeline()->controller()->getModel()) {
m_mainWindow->getCurrentTimeline()->controller()->getModel()->updateProfile(&getCurrentProfile()->profile());
checkProfileValidity();
}
return true;
}
return false;
}
void Core::checkProfileValidity()
{
int offset = (getCurrentProfile()->profile().width() % 8) + (getCurrentProfile()->profile().height() % 2);
if (offset > 0) {
// Profile is broken, warn user
if (m_binWidget) {
m_binWidget->displayBinMessage(i18n("Your project profile is invalid, rendering might fail."), KMessageWidget::Warning);
}
}
}
double Core::getCurrentSar() const
{
return getCurrentProfile()->sar();
}
double Core::getCurrentDar() const
{
return getCurrentProfile()->dar();
}
double Core::getCurrentFps() const
{
return getCurrentProfile()->fps();
}
QSize Core::getCurrentFrameDisplaySize() const
{
return {(int)(getCurrentProfile()->height() * getCurrentDar() + 0.5), getCurrentProfile()->height()};
}
QSize Core::getCurrentFrameSize() const
{
return {getCurrentProfile()->width(), getCurrentProfile()->height()};
}
void Core::requestMonitorRefresh()
{
if (!m_guiConstructed) return;
m_monitorManager->refreshProjectMonitor();
}
void Core::refreshProjectRange(QSize range)
{
if (!m_guiConstructed) return;
m_monitorManager->refreshProjectRange(range);
}
int Core::getItemPosition(const ObjectId &id)
{
if (!m_guiConstructed) return 0;
switch (id.first) {
case ObjectType::TimelineClip:
if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipPosition(id.second);
}
break;
case ObjectType::TimelineComposition:
if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isComposition(id.second)) {
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getCompositionPosition(id.second);
}
break;
case ObjectType::BinClip:
case ObjectType::TimelineTrack:
case ObjectType::Master:
return 0;
break;
default:
qDebug() << "ERROR: unhandled object type";
}
return 0;
}
int Core::getItemIn(const ObjectId &id)
{
if (!m_guiConstructed || !m_mainWindow->getCurrentTimeline() || !m_mainWindow->getCurrentTimeline()->controller()->getModel()) {
qDebug() << "/ / // QUERYING ITEM IN BUT GUI NOT BUILD!!";
return 0;
}
switch (id.first) {
case ObjectType::TimelineClip:
if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipIn(id.second);
} else {
qDebug()<<"// ERROR QUERYING NON CLIP PROPERTIES\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!";
}
break;
case ObjectType::TimelineComposition:
case ObjectType::BinClip:
case ObjectType::TimelineTrack:
case ObjectType::Master:
return 0;
break;
default:
qDebug() << "ERROR: unhandled object type";
}
return 0;
}
PlaylistState::ClipState Core::getItemState(const ObjectId &id)
{
if (!m_guiConstructed) return PlaylistState::Disabled;
switch (id.first) {
case ObjectType::TimelineClip:
if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipState(id.second);
}
break;
case ObjectType::TimelineComposition:
return PlaylistState::VideoOnly;
break;
case ObjectType::BinClip:
return m_binWidget->getClipState(id.second);
break;
case ObjectType::TimelineTrack:
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->isAudioTrack(id.second) ? PlaylistState::AudioOnly : PlaylistState::VideoOnly;
case ObjectType::Master:
return PlaylistState::Disabled;
break;
default:
qDebug() << "ERROR: unhandled object type";
break;
}
return PlaylistState::Disabled;
}
int Core::getItemDuration(const ObjectId &id)
{
if (!m_guiConstructed) return 0;
switch (id.first) {
case ObjectType::TimelineClip:
if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipPlaytime(id.second);
}
break;
case ObjectType::TimelineComposition:
if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isComposition(id.second)) {
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getCompositionPlaytime(id.second);
}
break;
case ObjectType::BinClip:
return (int)m_binWidget->getClipDuration(id.second);
break;
case ObjectType::TimelineTrack:
case ObjectType::Master:
return m_mainWindow->getCurrentTimeline()->controller()->duration();
default:
qDebug() << "ERROR: unhandled object type";
}
return 0;
}
int Core::getItemTrack(const ObjectId &id)
{
if (!m_guiConstructed) return 0;
switch (id.first) {
case ObjectType::TimelineClip:
case ObjectType::TimelineComposition:
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getItemTrackId(id.second);
break;
default:
qDebug() << "ERROR: unhandled object type";
}
return 0;
}
void Core::refreshProjectItem(const ObjectId &id)
{
if (!m_guiConstructed || m_mainWindow->getCurrentTimeline()->loading) return;
switch (id.first) {
case ObjectType::TimelineClip:
if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(id.second)) {
m_mainWindow->getCurrentTimeline()->controller()->refreshItem(id.second);
}
break;
case ObjectType::TimelineComposition:
if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isComposition(id.second)) {
m_mainWindow->getCurrentTimeline()->controller()->refreshItem(id.second);
}
break;
case ObjectType::TimelineTrack:
if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isTrack(id.second)) {
requestMonitorRefresh();
}
break;
case ObjectType::BinClip:
m_monitorManager->activateMonitor(Kdenlive::ClipMonitor);
m_monitorManager->refreshClipMonitor();
if (m_monitorManager->projectMonitorVisible() && m_mainWindow->getCurrentTimeline()->controller()->refreshIfVisible(id.second)) {
m_monitorManager->refreshTimer.start();
}
break;
case ObjectType::Master:
requestMonitorRefresh();
break;
default:
qDebug() << "ERROR: unhandled object type";
}
}
bool Core::hasTimelinePreview() const
{
if (!m_guiConstructed) {
return false;
}
return m_mainWindow->getCurrentTimeline()->controller()->renderedChunks().size() > 0;
}
KdenliveDoc *Core::currentDoc()
{
return m_projectManager->current();
}
int Core::projectDuration() const
{
if (!m_guiConstructed) {
return 0;
}
return m_mainWindow->getCurrentTimeline()->controller()->duration();
}
void Core::profileChanged()
{
GenTime::setFps(getCurrentFps());
}
void Core::pushUndo(const Fun &undo, const Fun &redo, const QString &text)
{
undoStack()->push(new FunctionalUndoCommand(undo, redo, text));
}
void Core::pushUndo(QUndoCommand *command)
{
undoStack()->push(command);
}
void Core::displayMessage(const QString &message, MessageType type, int timeout)
{
if (m_mainWindow) {
if (type == ProcessingJobMessage || type == OperationCompletedMessage) {
m_mainWindow->displayProgressMessage(message, type, timeout);
} else {
m_mainWindow->displayMessage(message, type, timeout);
}
} else {
qDebug() << message;
}
}
void Core::displayBinMessage(const QString &text, int type, const QList &actions)
{
m_binWidget->doDisplayMessage(text, (KMessageWidget::MessageType)type, actions);
}
void Core::displayBinLogMessage(const QString &text, int type, const QString &logInfo)
{
m_binWidget->doDisplayMessage(text, (KMessageWidget::MessageType)type, logInfo);
}
void Core::clearAssetPanel(int itemId)
{
if (m_guiConstructed) m_mainWindow->clearAssetPanel(itemId);
}
std::shared_ptr Core::getItemEffectStack(int itemType, int itemId)
{
if (!m_guiConstructed) return nullptr;
switch (itemType) {
case (int)ObjectType::TimelineClip:
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipEffectStack(itemId);
case (int)ObjectType::TimelineTrack:
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getTrackEffectStackModel(itemId);
break;
case (int)ObjectType::BinClip:
return m_binWidget->getClipEffectStack(itemId);
case (int)ObjectType::Master:
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getMasterEffectStackModel();
default:
return nullptr;
}
}
std::shared_ptr Core::undoStack()
{
return projectManager()->undoStack();
}
QMap Core::getTrackNames(bool videoOnly)
{
if (!m_guiConstructed) return QMap();
return m_mainWindow->getCurrentTimeline()->controller()->getTrackNames(videoOnly);
}
QPair Core::getCompositionATrack(int cid) const
{
if (!m_guiConstructed) return {};
return m_mainWindow->getCurrentTimeline()->controller()->getCompositionATrack(cid);
}
bool Core::compositionAutoTrack(int cid) const
{
return m_mainWindow->getCurrentTimeline()->controller()->compositionAutoTrack(cid);
}
void Core::setCompositionATrack(int cid, int aTrack)
{
if (!m_guiConstructed) return;
m_mainWindow->getCurrentTimeline()->controller()->setCompositionATrack(cid, aTrack);
}
std::shared_ptr Core::projectItemModel()
{
return m_projectItemModel;
}
void Core::invalidateRange(QSize range)
{
if (!m_mainWindow || m_mainWindow->getCurrentTimeline()->loading) return;
m_mainWindow->getCurrentTimeline()->controller()->invalidateZone(range.width(), range.height());
}
void Core::invalidateItem(ObjectId itemId)
{
if (!m_mainWindow || !m_mainWindow->getCurrentTimeline() || m_mainWindow->getCurrentTimeline()->loading) return;
switch (itemId.first) {
case ObjectType::TimelineClip:
case ObjectType::TimelineComposition:
m_mainWindow->getCurrentTimeline()->controller()->invalidateItem(itemId.second);
break;
case ObjectType::TimelineTrack:
m_mainWindow->getCurrentTimeline()->controller()->invalidateTrack(itemId.second);
break;
case ObjectType::BinClip:
m_binWidget->invalidateClip(QString::number(itemId.second));
break;
case ObjectType::Master:
m_mainWindow->getCurrentTimeline()->controller()->invalidateZone(0, -1);
break;
default:
// compositions should not have effects
break;
}
}
double Core::getClipSpeed(int id) const
{
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipSpeed(id);
}
void Core::updateItemKeyframes(ObjectId id)
{
if (id.first == ObjectType::TimelineClip && m_mainWindow) {
m_mainWindow->getCurrentTimeline()->controller()->updateClip(id.second, {TimelineModel::KeyframesRole});
}
}
void Core::updateItemModel(ObjectId id, const QString &service)
{
if (m_mainWindow && id.first == ObjectType::TimelineClip && !m_mainWindow->getCurrentTimeline()->loading && service.startsWith(QLatin1String("fade"))) {
bool startFade = service == QLatin1String("fadein") || service == QLatin1String("fade_from_black");
m_mainWindow->getCurrentTimeline()->controller()->updateClip(id.second, {startFade ? TimelineModel::FadeInRole : TimelineModel::FadeOutRole});
}
}
void Core::showClipKeyframes(ObjectId id, bool enable)
{
if (id.first == ObjectType::TimelineClip) {
m_mainWindow->getCurrentTimeline()->controller()->showClipKeyframes(id.second, enable);
} else if (id.first == ObjectType::TimelineComposition) {
m_mainWindow->getCurrentTimeline()->controller()->showCompositionKeyframes(id.second, enable);
}
}
Mlt::Profile *Core::thumbProfile()
{
QMutexLocker lck(&m_thumbProfileMutex);
if (!m_thumbProfile) {
m_thumbProfile = std::make_unique(m_currentProfile.toStdString().c_str());
m_thumbProfile->set_height(144);
int width = 144 * m_thumbProfile->dar() + 0.5;
if (width % 8 > 0) {
width += 8 - width % 8;
}
m_thumbProfile->set_width(width);
}
return m_thumbProfile.get();
}
int Core::getTimelinePosition() const
{
if (m_guiConstructed) {
return m_monitorManager->projectMonitor()->position();
}
return 0;
}
void Core::triggerAction(const QString &name)
{
QAction *action = m_mainWindow->actionCollection()->action(name);
if (action) {
action->trigger();
}
}
void Core::clean()
{
m_self.reset();
}
void Core::startMediaCapture(int tid, bool checkAudio, bool checkVideo)
{
if (checkAudio && checkVideo) {
m_capture->recordVideo(tid, true);
} else if (checkAudio) {
m_capture->recordAudio(tid, true);
}
m_mediaCaptureFile = m_capture->getCaptureOutputLocation();
}
void Core::stopMediaCapture(int tid, bool checkAudio, bool checkVideo)
{
if (checkAudio && checkVideo) {
m_capture->recordVideo(tid, false);
} else if (checkAudio) {
m_capture->recordAudio(tid, false);
}
}
QStringList Core::getAudioCaptureDevices()
{
return m_capture->getAudioCaptureDevices();
}
int Core::getMediaCaptureState()
{
return m_capture->getState();
}
bool Core::isMediaCapturing()
{
return m_capture->isRecording();
}
MediaCapture *Core::getAudioDevice()
{
return m_capture.get();
}
QString Core::getProjectFolderName()
{
if (currentDoc()) {
return currentDoc()->projectDataFolder() + QDir::separator();
}
return QString();
}
QString Core::getTimelineClipBinId(int cid)
{
if (!m_guiConstructed) {
return QString();
}
if (m_mainWindow->getCurrentTimeline()->controller()->getModel()->isClip(cid)) {
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipBinId(cid);
}
return QString();
}
int Core::getDurationFromString(const QString &time)
{
if (!m_guiConstructed) {
return 0;
}
const QString duration = currentDoc()->timecode().reformatSeparators(time);
return currentDoc()->timecode().getFrameCount(duration);
}
diff --git a/src/core.h b/src/core.h
index 61c7c303f..9904fc7e4 100644
--- a/src/core.h
+++ b/src/core.h
@@ -1,246 +1,248 @@
/*
Copyright (C) 2014 Till Theato
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 3 of the License, or
(at your option) any later version.
*/
#ifndef CORE_H
#define CORE_H
#include "definitions.h"
#include "kdenlivecore_export.h"
#include "undohelper.hpp"
#include
#include
#include
#include
#include
class Bin;
class DocUndoStack;
class EffectStackModel;
class JobManager;
class KdenliveDoc;
class LibraryWidget;
class MainWindow;
class MediaCapture;
class MixerManager;
class Monitor;
class MonitorManager;
class ProfileModel;
class ProjectItemModel;
class ProjectManager;
namespace Mlt {
class Repository;
class Profile;
} // namespace Mlt
#define EXIT_RESTART (42)
#define EXIT_CLEAN_RESTART (43)
#define pCore Core::self()
/**
* @class Core
* @brief Singleton that provides access to the different parts of Kdenlive
*
* Needs to be initialize before any widgets are created in MainWindow.
* Plugins should be loaded after the widget setup.
*/
class /*KDENLIVECORE_EXPORT*/ Core : public QObject
{
Q_OBJECT
public:
Core(const Core &) = delete;
Core &operator=(const Core &) = delete;
Core(Core &&) = delete;
Core &operator=(Core &&) = delete;
~Core() override;
/**
* @brief Setup the basics of the application, in particular the connection
* with Mlt
* @param isAppImage do we expect an AppImage (if yes, we use App path to deduce
* other binaries paths (melt, ffmpeg, etc)
* @param MltPath (optional) path to MLT environment
*/
static void build(bool isAppImage, const QString &MltPath = QString());
/**
* @brief Init the GUI part of the app and show the main window
* @param Url (optional) file to open
* If Url is present, it will be opened, otherwise, if openlastproject is
* set, latest project will be opened. If no file is open after trying this,
* a default new file will be created. */
void initGUI(const QUrl &Url);
/** @brief Returns a pointer to the singleton object. */
static std::unique_ptr &self();
/** @brief Delete the global core instance */
static void clean();
/** @brief Returns a pointer to the main window. */
MainWindow *window();
/** @brief Returns a pointer to the project manager. */
ProjectManager *projectManager();
/** @brief Returns a pointer to the current project. */
KdenliveDoc *currentDoc();
/** @brief Returns a pointer to the monitor manager. */
MonitorManager *monitorManager();
/** @brief Returns a pointer to the view of the project bin. */
Bin *bin();
/** @brief Select a clip in the Bin from its id. */
void selectBinClip(const QString &id, int frame = -1, const QPoint &zone = QPoint());
/** @brief Returns a pointer to the model of the project bin. */
std::shared_ptr projectItemModel();
/** @brief Returns a pointer to the job manager. Please do not store it. */
std::shared_ptr jobManager();
/** @brief Returns a pointer to the library. */
LibraryWidget *library();
/** @brief Returns a pointer to the audio mixer. */
MixerManager *mixer();
/** @brief Returns a pointer to MLT's repository */
std::unique_ptr &getMltRepository();
/** @brief Returns a pointer to the current profile */
std::unique_ptr &getCurrentProfile() const;
const QString &getCurrentProfilePath() const;
/** @brief Define the active profile
* @returns true if profile exists, false if not found
*/
bool setCurrentProfile(const QString &profilePath);
/** @brief Returns Sample Aspect Ratio of current profile */
double getCurrentSar() const;
/** @brief Returns Display Aspect Ratio of current profile */
double getCurrentDar() const;
/** @brief Returns frame rate of current profile */
double getCurrentFps() const;
/** @brief Returns the frame size (width x height) of current profile */
QSize getCurrentFrameSize() const;
/** @brief Returns the frame display size (width x height) of current profile */
QSize getCurrentFrameDisplaySize() const;
/** @brief Request project monitor refresh */
void requestMonitorRefresh();
/** @brief Request project monitor refresh if current position is inside range*/
void refreshProjectRange(QSize range);
/** @brief Request project monitor refresh if referenced item is under cursor */
void refreshProjectItem(const ObjectId &id);
/** @brief Returns a reference to a monitor (clip or project monitor) */
Monitor *getMonitor(int id);
/** @brief This function must be called whenever the profile used changes */
void profileChanged();
/** @brief Create and push and undo object based on the corresponding functions
Note that if you class permits and requires it, you should use the macro PUSH_UNDO instead*/
void pushUndo(const Fun &undo, const Fun &redo, const QString &text);
void pushUndo(QUndoCommand *command);
/** @brief display a user info/warning message in statusbar */
void displayMessage(const QString &message, MessageType type, int timeout = -1);
/** @brief Clear asset view if itemId is displayed. */
void clearAssetPanel(int itemId);
/** @brief Returns the effectstack of a given bin clip. */
std::shared_ptr getItemEffectStack(int itemType, int itemId);
int getItemPosition(const ObjectId &id);
int getItemIn(const ObjectId &id);
int getItemTrack(const ObjectId &id);
int getItemDuration(const ObjectId &id);
/** @brief Returns the capabilities of a clip: AudioOnly, VideoOnly or Disabled if both are allowed */
PlaylistState::ClipState getItemState(const ObjectId &id);
/** @brief Get a list of video track names with indexes */
QMap getTrackNames(bool videoOnly);
/** @brief Returns the composition A track (MLT index / Track id) */
QPair getCompositionATrack(int cid) const;
void setCompositionATrack(int cid, int aTrack);
/* @brief Return true if composition's a_track is automatic (no forced track)
*/
bool compositionAutoTrack(int cid) const;
std::shared_ptr undoStack();
double getClipSpeed(int id) const;
/** @brief Mark an item as invalid for timeline preview */
void invalidateItem(ObjectId itemId);
void invalidateRange(QSize range);
void prepareShutdown();
/** the keyframe model changed (effect added, deleted, active effect changed), inform timeline */
void updateItemKeyframes(ObjectId id);
/** A fade for clip id changed, update timeline */
void updateItemModel(ObjectId id, const QString &service);
/** Show / hide keyframes for a timeline clip */
void showClipKeyframes(ObjectId id, bool enable);
Mlt::Profile *thumbProfile();
/** @brief Returns the current project duration */
int projectDuration() const;
/** @brief Returns true if current project has some rendered timeline preview */
bool hasTimelinePreview() const;
/** @brief Returns current timeline cursor position */
int getTimelinePosition() const;
/** @brief Handles audio and video capture **/
void startMediaCapture(int tid, bool, bool);
void stopMediaCapture(int tid, bool, bool);
QStringList getAudioCaptureDevices();
int getMediaCaptureState();
bool isMediaCapturing();
MediaCapture *getAudioDevice();
/** @brief Returns Project Folder name for capture output location */
QString getProjectFolderName();
/** @brief Returns a timeline clip's bin id */
QString getTimelineClipBinId(int cid);
/** @brief Returns a frame duration from a timecode */
int getDurationFromString(const QString &time);
private:
explicit Core();
static std::unique_ptr m_self;
/** @brief Makes sure Qt's locale and system locale settings match. */
void initLocale();
MainWindow *m_mainWindow{nullptr};
ProjectManager *m_projectManager{nullptr};
MonitorManager *m_monitorManager{nullptr};
std::shared_ptr m_projectItemModel;
std::shared_ptr m_jobManager;
Bin *m_binWidget{nullptr};
LibraryWidget *m_library{nullptr};
MixerManager *m_mixerWidget{nullptr};
/** @brief Current project's profile path */
QString m_currentProfile;
QString m_profile;
std::unique_ptr m_thumbProfile;
bool m_guiConstructed = false;
/** @brief Check that the profile is valid (width is a multiple of 8 and height a multiple of 2 */
void checkProfileValidity();
std::unique_ptr m_capture;
QUrl m_mediaCaptureFile;
QMutex m_thumbProfileMutex;
public slots:
void triggerAction(const QString &name);
/** @brief display a user info/warning message in the project bin */
void displayBinMessage(const QString &text, int type, const QList &actions = QList());
void displayBinLogMessage(const QString &text, int type, const QString &logInfo);
+ /** @brief Create small thumbnails for luma used in compositions */
+ void buildLumaThumbs(const QStringList &values);
signals:
void coreIsReady();
void updateLibraryPath();
/** @brief Call config dialog on a selected page / tab */
void showConfigDialog(int, int);
void finalizeRecording(const QString &captureFile);
void autoScrollChanged();
};
#endif
diff --git a/src/mltconnection.cpp b/src/mltconnection.cpp
index 535b2786d..de8674e4f 100644
--- a/src/mltconnection.cpp
+++ b/src/mltconnection.cpp
@@ -1,206 +1,211 @@
/*
Copyright (C) 2007 Jean-Baptiste Mardelle
Copyright (C) 2014 Till Theato
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 3 of the License, or
(at your option) any later version.
*/
#include "mltconnection.h"
#include "core.h"
#include "kdenlivesettings.h"
#include "mainwindow.h"
#include "mlt_config.h"
#include
#include
#include
+#include
#include "kdenlive_debug.h"
#include
#include
#include
#include
std::unique_ptr MltConnection::m_self;
MltConnection::MltConnection(const QString &mltPath)
{
// Disable VDPAU that crashes in multithread environment.
// TODO: make configurable
setenv("MLT_NO_VDPAU", "1", 1);
m_repository = std::unique_ptr(Mlt::Factory::init());
locateMeltAndProfilesPath(mltPath);
// Retrieve the list of available producers.
QScopedPointer producers(m_repository->producers());
QStringList producersList;
int nb_producers = producers->count();
producersList.reserve(nb_producers);
for (int i = 0; i < nb_producers; ++i) {
producersList << producers->get_name(i);
}
KdenliveSettings::setProducerslist(producersList);
refreshLumas();
}
void MltConnection::construct(const QString &mltPath)
{
if (MltConnection::m_self) {
qDebug() << "DEBUG: Warning : trying to open a second mlt connection";
return;
}
MltConnection::m_self.reset(new MltConnection(mltPath));
}
std::unique_ptr &MltConnection::self()
{
return MltConnection::m_self;
}
void MltConnection::locateMeltAndProfilesPath(const QString &mltPath)
{
QString profilePath = mltPath;
// environment variables should override other settings
if ((profilePath.isEmpty() || !QFile::exists(profilePath)) && qEnvironmentVariableIsSet("MLT_PROFILES_PATH")) {
profilePath = qgetenv("MLT_PROFILES_PATH");
}
if ((profilePath.isEmpty() || !QFile::exists(profilePath)) && qEnvironmentVariableIsSet("MLT_DATA")) {
profilePath = qgetenv("MLT_DATA") + QStringLiteral("/profiles");
}
if ((profilePath.isEmpty() || !QFile::exists(profilePath)) && qEnvironmentVariableIsSet("MLT_PREFIX")) {
profilePath = qgetenv("MLT_PREFIX") + QStringLiteral("/share/mlt/profiles");
}
#ifndef Q_OS_WIN
// stored setting should not be considered on windows as MLT is distributed with each new Kdenlive version
if ((profilePath.isEmpty() || !QFile::exists(profilePath)) && !KdenliveSettings::mltpath().isEmpty()) profilePath = KdenliveSettings::mltpath();
#endif
// try to automatically guess MLT path if installed with the same prefix as kdenlive with default data path
if (profilePath.isEmpty() || !QFile::exists(profilePath)) {
profilePath = QDir::cleanPath(qApp->applicationDirPath() + QStringLiteral("/../share/mlt/profiles"));
}
// fallback to build-time definition
if ((profilePath.isEmpty() || !QFile::exists(profilePath)) && !QStringLiteral(MLT_DATADIR).isEmpty()) {
profilePath = QStringLiteral(MLT_DATADIR) + QStringLiteral("/profiles");
}
KdenliveSettings::setMltpath(profilePath);
#ifdef Q_OS_WIN
QString exeSuffix = ".exe";
#else
QString exeSuffix = "";
#endif
QString meltPath;
if (qEnvironmentVariableIsSet("MLT_PREFIX")) {
meltPath = qgetenv("MLT_PREFIX") + QStringLiteral("/bin/melt") + exeSuffix;
} else {
meltPath = KdenliveSettings::rendererpath();
}
if (!QFile::exists(meltPath)) {
meltPath = QDir::cleanPath(profilePath + QStringLiteral("/../../../bin/melt")) + exeSuffix;
if (!QFile::exists(meltPath)) {
meltPath = QStandardPaths::findExecutable("melt");
if (meltPath.isEmpty()) {
meltPath = QStandardPaths::findExecutable("mlt-melt");
}
}
}
KdenliveSettings::setRendererpath(meltPath);
if (meltPath.isEmpty() && !qEnvironmentVariableIsSet("MLT_TESTS")) {
// Cannot find the MLT melt renderer, ask for location
QScopedPointer getUrl(
new KUrlRequesterDialog(QUrl(), i18n("Cannot find the melt program required for rendering (part of MLT)"), pCore->window()));
if (getUrl->exec() == QDialog::Rejected) {
::exit(0);
} else {
meltPath = getUrl->selectedUrl().toLocalFile();
if (meltPath.isEmpty()) {
::exit(0);
} else {
KdenliveSettings::setRendererpath(meltPath);
}
}
}
if (profilePath.isEmpty()) {
profilePath = QDir::cleanPath(meltPath + QStringLiteral("/../../share/mlt/profiles"));
KdenliveSettings::setMltpath(profilePath);
}
QStringList profilesFilter;
profilesFilter << QStringLiteral("*");
QStringList profilesList = QDir(profilePath).entryList(profilesFilter, QDir::Files);
if (profilesList.isEmpty()) {
// Cannot find MLT path, try finding melt
if (!meltPath.isEmpty()) {
if (meltPath.contains(QLatin1Char('/'))) {
profilePath = meltPath.section(QLatin1Char('/'), 0, -2) + QStringLiteral("/share/mlt/profiles");
} else {
profilePath = qApp->applicationDirPath() + QStringLiteral("/share/mlt/profiles");
}
profilePath = QStringLiteral("/usr/local/share/mlt/profiles");
KdenliveSettings::setMltpath(profilePath);
profilesList = QDir(profilePath).entryList(profilesFilter, QDir::Files);
}
if (profilesList.isEmpty()) {
// Cannot find the MLT profiles, ask for location
QScopedPointer getUrl(
new KUrlRequesterDialog(QUrl::fromLocalFile(profilePath), i18n("Cannot find your MLT profiles, please give the path"), pCore->window()));
getUrl->urlRequester()->setMode(KFile::Directory);
if (getUrl->exec() == QDialog::Rejected) {
::exit(0);
} else {
profilePath = getUrl->selectedUrl().toLocalFile();
if (profilePath.isEmpty()) {
::exit(0);
} else {
KdenliveSettings::setMltpath(profilePath);
profilesList = QDir(profilePath).entryList(profilesFilter, QDir::Files);
}
}
}
}
qCDebug(KDENLIVE_LOG) << "MLT profiles path: " << KdenliveSettings::mltpath();
// Parse again MLT profiles to build a list of available video formats
if (profilesList.isEmpty()) {
locateMeltAndProfilesPath();
}
}
std::unique_ptr &MltConnection::getMltRepository()
{
return m_repository;
}
void MltConnection::refreshLumas()
{
// Check for Kdenlive installed luma files, add empty string at start for no luma
QStringList fileFilters;
MainWindow::m_lumaFiles.clear();
fileFilters << QStringLiteral("*.png") << QStringLiteral("*.pgm");
QStringList customLumas = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("lumas"), QStandardPaths::LocateDirectory);
customLumas.append(QString(mlt_environment("MLT_DATA")) + QStringLiteral("/lumas"));
+ QStringList allImagefiles;
for (const QString &folder : customLumas) {
QDir topDir(folder);
QStringList folders = topDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
QString format;
for (const QString &f : folders) {
QStringList imagefiles;
QDir dir(topDir.absoluteFilePath(f));
if (f == QLatin1String("HD")) {
format = QStringLiteral("16_9");
} else {
format = f;
}
QStringList filesnames = dir.entryList(fileFilters, QDir::Files);
if (MainWindow::m_lumaFiles.contains(format)) {
imagefiles = MainWindow::m_lumaFiles.value(format);
}
for (const QString &fname : filesnames) {
imagefiles.append(dir.absoluteFilePath(fname));
}
MainWindow::m_lumaFiles.insert(format, imagefiles);
+ allImagefiles << imagefiles;
}
}
+ allImagefiles.removeDuplicates();
+ QtConcurrent::run(pCore.get(), &Core::buildLumaThumbs, allImagefiles);
}