Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit a99ec9e9 authored by Vincent Pinon's avatar Vincent Pinon

Explain user if import/export is not available

parent 7c404235
Pipeline #17486 passed with stage
in 14 minutes and 37 seconds
...@@ -433,7 +433,6 @@ void MainWindow::init() ...@@ -433,7 +433,6 @@ void MainWindow::init()
new HideTitleBars(this); new HideTitleBars(this);
m_extraFactory = new KXMLGUIClient(this); m_extraFactory = new KXMLGUIClient(this);
buildDynamicActions(); buildDynamicActions();
m_otioConvertions.getOtioConverters();
// Create Effect Basket (dropdown list of favorites) // Create Effect Basket (dropdown list of favorites)
m_effectBasket = new EffectBasket(this); m_effectBasket = new EffectBasket(this);
...@@ -1306,11 +1305,9 @@ void MainWindow::setupActions() ...@@ -1306,11 +1305,9 @@ void MainWindow::setupActions()
addAction(QStringLiteral("transcode_clip"), i18n("Transcode Clips"), this, SLOT(slotTranscodeClip()), QIcon::fromTheme(QStringLiteral("edit-copy"))); addAction(QStringLiteral("transcode_clip"), i18n("Transcode Clips"), this, SLOT(slotTranscodeClip()), QIcon::fromTheme(QStringLiteral("edit-copy")));
QAction *exportAction = new QAction(QIcon::fromTheme(QStringLiteral("document-export")), i18n("E&xport project"), this); QAction *exportAction = new QAction(QIcon::fromTheme(QStringLiteral("document-export")), i18n("E&xport project"), this);
connect(exportAction, &QAction::triggered, &m_otioConvertions, &OtioConvertions::slotExportProject); connect(exportAction, &QAction::triggered, &m_otioConvertions, &OtioConvertions::slotExportProject);
exportAction->setEnabled(false);
addAction(QStringLiteral("export_project"), exportAction); addAction(QStringLiteral("export_project"), exportAction);
QAction *importAction = new QAction(QIcon::fromTheme(QStringLiteral("document-import")), i18n("&Import project"), this); QAction *importAction = new QAction(QIcon::fromTheme(QStringLiteral("document-import")), i18n("&Import project"), this);
connect(importAction, &QAction::triggered, &m_otioConvertions, &OtioConvertions::slotImportProject); connect(importAction, &QAction::triggered, &m_otioConvertions, &OtioConvertions::slotImportProject);
importAction->setEnabled(false);
addAction(QStringLiteral("import_project"), importAction); addAction(QStringLiteral("import_project"), importAction);
addAction(QStringLiteral("archive_project"), i18n("Archive Project"), this, SLOT(slotArchiveProject()), addAction(QStringLiteral("archive_project"), i18n("Archive Project"), this, SLOT(slotArchiveProject()),
......
...@@ -33,45 +33,53 @@ OtioConvertions::OtioConvertions() ...@@ -33,45 +33,53 @@ OtioConvertions::OtioConvertions()
{ {
} }
void OtioConvertions::getOtioConverters() bool OtioConvertions::getOtioConverters()
{ {
if(QStandardPaths::findExecutable(QStringLiteral("otioconvert")).isEmpty() || if(QStandardPaths::findExecutable(QStringLiteral("otioconvert")).isEmpty()) {
QStandardPaths::findExecutable(QStringLiteral("python3")).isEmpty()) { KMessageBox::error(pCore->window(), i18n("Could not find \"otioconvert\" script.\n"
qInfo("otioconvert or python3 not available, project import/export not enabled"); "You need to install OpenTimelineIO,\n"
return; "through your package manager if available,\n"
"or by \"pip3 install opentimelineio\",\n"
"and check the scripts are installed in a directory "
"listed in PATH environment variable"));
return false;
} }
connect(&m_otioProcess, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &OtioConvertions::slotGotOtioConverters); if(QStandardPaths::findExecutable(QStringLiteral("python3")).isEmpty()) {
m_otioProcess.start(QStringLiteral("python3")); KMessageBox::error(pCore->window(), ("Could not find \"python3\" executable, needed for OpenTimelineIO adapters.\n"
m_otioProcess.write(QStringLiteral( "If already installed, check it is installed in a directory"
"from opentimelineio import *\n" "listed in PATH environment variable"));
"for a in plugins.ActiveManifest().adapters:\n" return false;
" if a.has_feature('read') and a.has_feature('write'):\n" }
" print('*.'+' *.'.join(a.suffixes), end=' ')" QProcess listAdapters;
).toUtf8()); listAdapters.start(QStringLiteral("python3"));
m_otioProcess.closeWriteChannel(); listAdapters.write(QStringLiteral(
} "from opentimelineio import *\n"
"for a in plugins.ActiveManifest().adapters:\n"
void OtioConvertions::slotGotOtioConverters(int exitCode, QProcess::ExitStatus exitStatus) " if a.has_feature('read') and a.has_feature('write'):\n"
{ " print('*.'+' *.'.join(a.suffixes), end=' ')"
m_otioProcess.disconnect(); ).toUtf8());
if(exitStatus != QProcess::NormalExit || exitCode != 0) { listAdapters.closeWriteChannel();
qInfo("OpenTimelineIO python module is not available"); listAdapters.waitForFinished();
return; if(listAdapters.exitStatus() != QProcess::NormalExit || listAdapters.exitCode() != 0) {
KMessageBox::error(pCore->window(), i18n("python3 could not load opentimelineio module"));
return false;
} }
m_adapters = m_otioProcess.readAll(); m_adapters = listAdapters.readAll();
qInfo() << "OTIO adapters:" << m_adapters;
if (!m_adapters.contains("kdenlive")) { if (!m_adapters.contains("kdenlive")) {
qInfo() << "Kdenlive not supported by OTIO: " << m_adapters; KMessageBox::error(pCore->window(), i18n("Your OpenTimelineIO module does not include Kdenlive adapter.\n"
return; "Please install version >= 0.12\n"));
return false;
} }
QAction *exportAction = pCore->window()->actionCollection()->action("export_project"); return true;
QAction *importAction = pCore->window()->actionCollection()->action("import_project");
exportAction->setEnabled(true);
importAction->setEnabled(true);
} }
void OtioConvertions::slotExportProject() void OtioConvertions::slotExportProject()
{ {
auto exportFile = QFileDialog::getSaveFileName( if(m_adapters.isEmpty() && !getOtioConverters()) {
return;
}
QString exportFile = QFileDialog::getSaveFileName(
pCore->window(), i18n("Export Project"), pCore->window(), i18n("Export Project"),
pCore->currentDoc()->projectDataFolder(), pCore->currentDoc()->projectDataFolder(),
i18n("OpenTimelineIO adapters (%1)", m_adapters)); i18n("OpenTimelineIO adapters (%1)", m_adapters));
...@@ -83,21 +91,32 @@ void OtioConvertions::slotExportProject() ...@@ -83,21 +91,32 @@ void OtioConvertions::slotExportProject()
KMessageBox::error(pCore->window(), i18n("Project file could not be saved for export.")); KMessageBox::error(pCore->window(), i18n("Project file could not be saved for export."));
return; return;
} }
m_otioTempFile.setFileTemplate(QStringLiteral("XXXXXX.kdenlive")); QTemporaryFile tmp;
if (!m_otioTempFile.open() || !(m_otioTempFile.write(xml) > 0)) { tmp.setFileTemplate(QStringLiteral("XXXXXX.kdenlive"));
pCore->displayMessage(i18n("Unable to write to temporary kdenlive file for export: %1", if (!tmp.open() || !(tmp.write(xml) > 0)) {
m_otioTempFile.fileName()), ErrorMessage); KMessageBox::error(pCore->window(), i18n("Unable to write to temporary kdenlive file for export: %1",
tmp.fileName()));
return; return;
} }
connect(&m_otioProcess, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), QProcess convert;
this, &OtioConvertions::slotProjectExported); convert.start(QStringLiteral("otioconvert"), {"-i", tmp.fileName(), "-o", exportFile});
m_otioProcess.start(QStringLiteral("otioconvert"), {"-i", m_otioTempFile.fileName(), "-o", exportFile}); convert.waitForFinished();
tmp.remove();
if(convert.exitStatus() != QProcess::NormalExit || convert.exitCode() != 0) {
KMessageBox::error(pCore->window(), i18n("Project conversion failed:\n%1"),
QString(convert.readAllStandardError()));
return;
}
pCore->displayMessage(i18n("Project conversion complete"), InformationMessage);
} }
void OtioConvertions::slotImportProject() void OtioConvertions::slotImportProject()
{ {
if(m_adapters.isEmpty() && !getOtioConverters()) {
return;
}
// Select foreign project to import // Select foreign project to import
auto importFile = QFileDialog::getOpenFileName( QString importFile = QFileDialog::getOpenFileName(
pCore->window(), i18n("Project to import"), pCore->window(), i18n("Project to import"),
pCore->currentDoc()->projectDataFolder(), pCore->currentDoc()->projectDataFolder(),
i18n("OpenTimelineIO adapters (%1)", m_adapters)); i18n("OpenTimelineIO adapters (%1)", m_adapters));
...@@ -105,47 +124,30 @@ void OtioConvertions::slotImportProject() ...@@ -105,47 +124,30 @@ void OtioConvertions::slotImportProject()
return; return;
} }
// Select converted project file // Select converted project file
m_importedFile = QFileDialog::getSaveFileName( QString importedFile = QFileDialog::getSaveFileName(
pCore->window(), i18n("Imported Project"), pCore->window(), i18n("Imported Project"),
pCore->currentDoc()->projectDataFolder(), pCore->currentDoc()->projectDataFolder(),
i18n("Kdenlive project (*.kdenlive)")); i18n("Kdenlive project (*.kdenlive)"));
if (m_importedFile.isNull()) { if (importedFile.isNull()) {
return; return;
} }
// Start convertion process // Start convertion process
connect(&m_otioProcess, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), QProcess convert;
this, &OtioConvertions::slotProjectImported); convert.start(QStringLiteral("otioconvert"), {"-i", importFile, "-o", importedFile});
m_otioProcess.start(QStringLiteral("otioconvert"), {"-i", importFile, "-o", m_importedFile}); convert.waitForFinished();
} if(convert.exitStatus() != QProcess::NormalExit || convert.exitCode() != 0 || !QFile::exists(importedFile)) {
KMessageBox::error(pCore->window(), i18n("Project conversion failed:\n%1"),
void OtioConvertions::slotProjectExported(int exitCode, QProcess::ExitStatus exitStatus) QString(convert.readAllStandardError()));
{
m_otioProcess.disconnect();
m_otioTempFile.remove();
if(exitStatus != QProcess::NormalExit || exitCode != 0) {
pCore->displayMessage(i18n("Project conversion failed"), ErrorMessage);
qWarning() << exitCode << exitStatus << QString(m_otioProcess.readAllStandardError());
return;
}
pCore->displayMessage(i18n("Project conversion complete"), InformationMessage);
}
void OtioConvertions::slotProjectImported(int exitCode, QProcess::ExitStatus exitStatus)
{
m_otioProcess.disconnect();
if(exitStatus != QProcess::NormalExit || exitCode != 0 || !QFile::exists(m_importedFile)) {
pCore->displayMessage(i18n("Project conversion failed"), ErrorMessage);
qWarning() << exitCode << exitStatus << QString(m_otioProcess.readAllStandardError());
return; return;
} }
pCore->displayMessage(i18n("Project conversion complete"), InformationMessage); pCore->displayMessage(i18n("Project conversion complete"), InformationMessage);
// Verify current project can be closed // Verify current project can be closed
if (pCore->currentDoc()->isModified() && if (pCore->currentDoc()->isModified() &&
KMessageBox::warningContinueCancel(pCore->window(), i18n( KMessageBox::warningContinueCancel(pCore->window(), i18n(
"The current project has not been saved\n" "The current project has not been saved\n"
"Do you want to load imported project abandoning latest changes?") "Do you want to load imported project abandoning latest changes?")
) != KMessageBox::Continue) { ) != KMessageBox::Continue) {
return; return;
} }
pCore->projectManager()->openFile(QUrl::fromLocalFile(m_importedFile)); pCore->projectManager()->openFile(QUrl::fromLocalFile(importedFile));
} }
...@@ -31,22 +31,14 @@ class OtioConvertions: public QObject ...@@ -31,22 +31,14 @@ class OtioConvertions: public QObject
Q_OBJECT Q_OBJECT
public: public:
OtioConvertions(); OtioConvertions();
void getOtioConverters(); bool getOtioConverters();
private: private:
QProcess m_otioProcess;
QString m_adapters; QString m_adapters;
QTemporaryFile m_otioTempFile;
QString m_importedFile;
public slots: public slots:
void slotExportProject(); void slotExportProject();
void slotImportProject(); void slotImportProject();
private slots:
void slotGotOtioConverters(int exitCode, QProcess::ExitStatus exitStatus);
void slotProjectExported(int exitCode, QProcess::ExitStatus exitStatus);
void slotProjectImported(int exitCode, QProcess::ExitStatus exitStatus);
}; };
#endif // OTIOCONVERTIONS_H #endif // OTIOCONVERTIONS_H
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