From d2409500e164bbae2245085ff85da037c1f843de Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Tue, 24 Nov 2020 18:15:13 +0100 Subject: [PATCH] Subtitles: work on temp files until we save the project so that each change to the subtitles is not instantly saved --- src/bin/model/subtitlemodel.cpp | 32 ++++++++++++++++--- src/bin/model/subtitlemodel.hpp | 4 ++- src/doc/kdenlivedoc.cpp | 20 ++++-------- src/doc/kdenlivedoc.h | 4 +-- .../effectstack/model/effectstackmodel.cpp | 3 +- src/mainwindow.cpp | 18 ++++++++--- src/mainwindow.h | 2 +- src/project/projectmanager.cpp | 5 +-- 8 files changed, 55 insertions(+), 33 deletions(-) diff --git a/src/bin/model/subtitlemodel.cpp b/src/bin/model/subtitlemodel.cpp index 14990ddfe..0e84395e2 100644 --- a/src/bin/model/subtitlemodel.cpp +++ b/src/bin/model/subtitlemodel.cpp @@ -34,9 +34,11 @@ #include #include +#include #include #include #include +#include SubtitleModel::SubtitleModel(Mlt::Tractor *tractor, std::shared_ptr timeline, QObject *parent) : QAbstractListModel(parent) @@ -837,11 +839,30 @@ QString SubtitleModel::toJson() return QString(jsonDoc.toJson()); } -void SubtitleModel::jsontoSubtitle(const QString &data, QString updatedFileName) +void SubtitleModel::copySubtitle(const QString &path, bool checkOverwrite) { - QString outFile = updatedFileName.isEmpty() ? m_subtitleFilter->get("av.filename") : updatedFileName; - if (outFile.isEmpty()) { - outFile = pCore->currentDoc()->subTitlePath(); // use srt format as default unless file is imported (m_subFilePath) + QFile srcFile(pCore->currentDoc()->subTitlePath(false)); + if (srcFile.exists()) { + QFile prev(path); + if (prev.exists()) { + if (checkOverwrite || !path.endsWith(QStringLiteral(".srt"))) { + if (KMessageBox::questionYesNo(QApplication::activeWindow(), i18n("File %1 already exists.\nDo you want to overwrite it?", path)) == KMessageBox::No) { + return; + } + } + prev.remove(); + } + srcFile.copy(path); + } +} + + +void SubtitleModel::jsontoSubtitle(const QString &data) +{ + QString outFile = pCore->currentDoc()->subTitlePath(false); + QString masterFile = m_subtitleFilter->get("av.filename"); + if (masterFile.isEmpty()) { + m_subtitleFilter->set("av.filename", outFile.toUtf8().constData()); } bool assFormat = outFile.endsWith(".ass"); if (!assFormat) { @@ -927,8 +948,9 @@ void SubtitleModel::jsontoSubtitle(const QString &data, QString updatedFileName) //qDebug() << "ADDING SUBTITLE to FILE AT START POS: " << startPos <<" END POS: "<getCurrentFps(); } + outF.close(); } - qDebug()<<"Setting subtitle filter: "< 0) { m_subtitleFilter->set("av.filename", outFile.toUtf8().constData()); m_tractor->attach(*m_subtitleFilter.get()); diff --git a/src/bin/model/subtitlemodel.hpp b/src/bin/model/subtitlemodel.hpp index 17380f019..cdfdb27d3 100644 --- a/src/bin/model/subtitlemodel.hpp +++ b/src/bin/model/subtitlemodel.hpp @@ -128,13 +128,15 @@ public: GenTime getStartPosForId(int id) const; int getPreviousSub(int id) const; int getNextSub(int id) const; + /** @brief Copy subtitle file to a new path */ + void copySubtitle(const QString &path, bool checkOverwrite); public slots: /** @brief Function that parses through a subtitle file */ void parseSubtitle(const QString subPath = QString()); /** @brief Import model to a temporary subtitle file to which the Subtitle effect is applied*/ - void jsontoSubtitle(const QString &data, QString updatedFileName = QString()); + void jsontoSubtitle(const QString &data); /** @brief Update a subtitle text*/ bool setText(int id, const QString text); diff --git a/src/doc/kdenlivedoc.cpp b/src/doc/kdenlivedoc.cpp index bb95ff4e6..7947d61b9 100644 --- a/src/doc/kdenlivedoc.cpp +++ b/src/doc/kdenlivedoc.cpp @@ -762,19 +762,11 @@ void KdenliveDoc::setUrl(const QUrl &url) void KdenliveDoc::updateSubtitle(QString newUrl) { if (auto ptr = m_subtitleModel.lock()) { - if (newUrl.isEmpty() && m_url.isValid()) { - newUrl = m_url.toLocalFile(); - } QString subPath; - if (newUrl.isEmpty()) { - subPath = subTitlePath(); - } else { - // Update path of subtitle file - QString documentId = QDir::cleanPath(getDocumentProperty(QStringLiteral("documentid"))); - QFileInfo info(newUrl); - subPath = info.dir().absoluteFilePath(QString("%1.srt").arg(info.fileName())); - } - ptr->jsontoSubtitle(ptr->toJson(), subPath); + bool checkOverwrite = QUrl::fromLocalFile(newUrl) != m_url; + QFileInfo info(newUrl); + subPath = info.dir().absoluteFilePath(QString("%1.srt").arg(info.fileName())); + ptr->copySubtitle(subPath, checkOverwrite); } } @@ -1793,11 +1785,11 @@ QString& KdenliveDoc::modifiedDecimalPoint() { return m_modifiedDecimalPoint; } -QString KdenliveDoc::subTitlePath() +const QString KdenliveDoc::subTitlePath(bool final) { QString path; QString documentId = QDir::cleanPath(getDocumentProperty(QStringLiteral("documentid"))); - if (m_url.isValid()) { + if (m_url.isValid() && final) { return QFileInfo(m_url.toLocalFile()).dir().absoluteFilePath(QString("%1.srt").arg(m_url.fileName())); } else { path = QDir::temp().absoluteFilePath(QString("%1.srt").arg(documentId)); diff --git a/src/doc/kdenlivedoc.h b/src/doc/kdenlivedoc.h index 2bf21ac2e..c8e39c594 100644 --- a/src/doc/kdenlivedoc.h +++ b/src/doc/kdenlivedoc.h @@ -174,8 +174,8 @@ public: QString &modifiedDecimalPoint(); /** @brief Initialize subtitle model */ void initializeSubtitles(const std::shared_ptr m_subtitle); - /** @brief Returns a path for current document's subtitle file */ - QString subTitlePath(); + /** @brief Returns a path for current document's subtitle file. If final is true, this will be the project filename with ".srt" appended. Otherwise a file in /tmp */ + const QString subTitlePath(bool final); private: QUrl m_url; diff --git a/src/effects/effectstack/model/effectstackmodel.cpp b/src/effects/effectstack/model/effectstackmodel.cpp index c19d98ebe..1660149b9 100644 --- a/src/effects/effectstack/model/effectstackmodel.cpp +++ b/src/effects/effectstack/model/effectstackmodel.cpp @@ -921,8 +921,7 @@ void EffectStackModel::importEffects(const std::weak_ptr &service, // Required to load master audio effects if (m_ownerId.first == ObjectType::Master && filter->get("mlt_service") == QLatin1String("avfilter.subtitles")) { // A subtitle filter, update project - QString subFile(filter->get("av.filename")); - pCore->window()->slotEditSubtitle(subFile); + pCore->window()->slotEditSubtitle(true); } else if (auto ms = m_masterService.lock()) { ms->attach(*filter.get()); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 36a3529a8..a5f99bfa0 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -4194,9 +4194,16 @@ void MainWindow::resetSubtitles() m_buttonSubtitleEditTool->setChecked(false); getMainTimeline()->showSubtitles = false; pCore->subtitleWidget()->setModel(nullptr); + if (pCore->currentDoc()) { + const QString workPath = pCore->currentDoc()->subTitlePath(false); + QFile workFile(workPath); + if (workFile.exists()) { + workFile.remove(); + } + } } -void MainWindow::slotEditSubtitle(QString subPath) +void MainWindow::slotEditSubtitle(bool loadExisting) { std::shared_ptr subtitleModel = pCore->getSubtitleModel(); if (subtitleModel == nullptr) { @@ -4205,10 +4212,13 @@ void MainWindow::slotEditSubtitle(QString subPath) getMainTimeline()->controller()->getModel()->setSubModel(subtitleModel); pCore->currentDoc()->initializeSubtitles(subtitleModel); pCore->subtitleWidget()->setModel(subtitleModel); - if (!subPath.isEmpty() && QFileInfo(subPath).isRelative()) { - subPath.prepend(pCore->currentDoc()->documentRoot()); + const QString subPath = pCore->currentDoc()->subTitlePath(true); + const QString workPath = pCore->currentDoc()->subTitlePath(false); + QFile subFile(subPath); + if (subFile.exists()) { + subFile.copy(workPath); + subtitleModel->parseSubtitle(workPath); } - subtitleModel->parseSubtitle(subPath); getMainTimeline()->showSubtitles = true; m_buttonSubtitleEditTool->setChecked(true); getMainTimeline()->connectSubtitleModel(true); diff --git a/src/mainwindow.h b/src/mainwindow.h index e8ee7e6e3..e471e75f5 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -298,7 +298,7 @@ public slots: void slotSwitchTimelineZone(bool toggled); /** @brief Open the online services search dialog. */ void slotDownloadResources(); - void slotEditSubtitle(QString subPath = QString()); + void slotEditSubtitle(bool loadExisting = false); private slots: /** @brief Shows the shortcut dialog. */ diff --git a/src/project/projectmanager.cpp b/src/project/projectmanager.cpp index 30d48a85a..24928d8b0 100644 --- a/src/project/projectmanager.cpp +++ b/src/project/projectmanager.cpp @@ -295,9 +295,7 @@ bool ProjectManager::saveFileAs(const QString &outputFileName, bool saveACopy) // Sync document properties prepareSave(); QString saveFolder = QFileInfo(outputFileName).absolutePath(); - if (!saveACopy) { - m_project->updateSubtitle(outputFileName); - } + m_project->updateSubtitle(outputFileName); QString scene = projectSceneList(saveFolder); if (!m_replacementPattern.isEmpty()) { QMapIterator i(m_replacementPattern); @@ -307,7 +305,6 @@ bool ProjectManager::saveFileAs(const QString &outputFileName, bool saveACopy) } } if (!m_project->saveSceneList(outputFileName, scene)) { - m_project->updateSubtitle(); return false; } QUrl url = QUrl::fromLocalFile(outputFileName); -- GitLab