diff --git a/src/Lib/Ass/AssFactory.cc b/src/Lib/Ass/AssFactory.cc index 334de5b8b3e1fc18514958faf63b3684aac84cc0..7bd08bfe0792fd013662a72a85b931b5a8b4dd47 100644 --- a/src/Lib/Ass/AssFactory.cc +++ b/src/Lib/Ass/AssFactory.cc @@ -120,6 +120,19 @@ AssFactory::AssFactory(const QString &fileName) throw std::runtime_error("the loaded ass is invalid"); } +AssFactory::AssFactory(const QJsonValue &internal) + : diskStorage("") +{ + if (!diskStorage.open(QIODevice::ReadOnly | QIODevice::Text)) + throw std::runtime_error("failed to open file for reading"); + + if (!initFromStorage()) + throw std::runtime_error("failed to init ass factory from file"); + + if (!checkValidity()) + throw std::runtime_error("the loaded ass is invalid"); +} + void AssFactory::getStyles(QVector<StylePtr> &ret) const noexcept { diff --git a/src/Lib/Ass/AssFactory.hh b/src/Lib/Ass/AssFactory.hh index 8e1812889b07cf4fb7183943662d6a6fb56d0b54..544806afe3c7b608ca4ad65dd254b438abc970a7 100644 --- a/src/Lib/Ass/AssFactory.hh +++ b/src/Lib/Ass/AssFactory.hh @@ -46,6 +46,7 @@ private: public: explicit AssFactory(const QString &); + explicit AssFactory(const QJsonValue &); ~AssFactory() noexcept = default; bool hasStyle(const QString &) const noexcept; diff --git a/src/Lib/Document/CRTPSubDocument.hh b/src/Lib/Document/CRTPSubDocument.hh index 7aea6cf7871c4a7caf0167ac79f998ad16e38de6..a32869f9ecf4daff7b710c399bd120b038c7fa68 100644 --- a/src/Lib/Document/CRTPSubDocument.hh +++ b/src/Lib/Document/CRTPSubDocument.hh @@ -129,7 +129,25 @@ class AssSubDocument final : public CRTPSubDocument<AssDocumentType, AssSubDocum static constexpr inline bool hasContext = false; const QStringList &suffixList = Vivy::Utils::assFileSuffix; +public: + static std::unique_ptr<AssSubDocument> fromInternal(const QJsonValue &internal) noexcept + { + auto ret = std::unique_ptr<AssSubDocument>(new AssSubDocument()); + ret->logDebug() << "Init ASS subdocument from internal"; + + try { + ret->initFromInternal(internal); // May throw + } catch (const std::runtime_error &e) { + ret->logDebug() << "Failed to init ASS subdocument from internal: " << e.what(); + ret.reset(); + } + + return ret; + } + +private: void initFromPath(const QString &); + void initFromInternal(const QJsonValue &); explicit AssSubDocument() noexcept = default; friend CRTPSubDocument<AssDocumentType, AssSubDocument, void>; @@ -143,9 +161,14 @@ public: const QVector<Ass::LinePtr> &getLines() const noexcept; const QVector<Ass::StylePtr> &getStyles() const noexcept; + void setFilePath(QString filepath) noexcept; + void setInternalAss(bool b) noexcept; + bool haveInternalAss() const noexcept; + private: QVector<Ass::StylePtr> styles; QVector<Ass::LinePtr> lines; Ass::AssFactory *assFactory; + bool internalAss{ false }; }; } diff --git a/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc b/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc index 9f55a6f3a722b98accb463def72b8ba59e1a7af2..a1266bf8ce4ea84107e564bb268d85ab9b106fb8 100644 --- a/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc +++ b/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc @@ -15,6 +15,16 @@ AssSubDocument::initFromPath(const QString &path) assFactory->getLines(lines); } +void +AssSubDocument::initFromInternal(const QJsonValue &internal) +{ + styles.clear(); + lines.clear(); + assFactory = new Ass::AssFactory(internal); + assFactory->getStyles(styles); + assFactory->getLines(lines); +} + QString AssSubDocument::getElementName() const noexcept { @@ -53,6 +63,18 @@ AssSubDocument::getFactory() noexcept return assFactory; } +bool +AssSubDocument::haveInternalAss() const noexcept +{ + return internalAss; +} + +void +AssSubDocument::setInternalAss(bool b) noexcept +{ + internalAss = b; +} + QJsonArray AssSubDocument::getInternalAss() noexcept { @@ -64,3 +86,9 @@ AssSubDocument::getInternalAss() noexcept return ret; } + +void +AssSubDocument::setFilePath(QString filepath) noexcept +{ + filePath = filepath; +} diff --git a/src/Lib/Document/VivyDocument.cc b/src/Lib/Document/VivyDocument.cc index baf0113ea79a285a7a690b4ddcd3e874d9f38e8d..8dc4064c017be92d214df16c30e65e9320c3f269 100644 --- a/src/Lib/Document/VivyDocument.cc +++ b/src/Lib/Document/VivyDocument.cc @@ -89,6 +89,26 @@ VivyDocument::loadSaveJsonDocumentFile_ALPHA(VivyDocument *const self, const QJs if (!self->loadSubDocument(ass.toString(), Capabilities::AssAble)) throw std::runtime_error("Failed to load ASS sub document"); } + + /* + * TODO: for now, if there is an internal ass we use it and ignore the SubAss file + * In the future, both should be loaded to allow the user to switch between the 2 + * (e.g. a "reference" ass and the vivy ass) + */ + if (QJsonValue haveInternalAss = json[KeySubDocuments][KeyHaveInternalAss]; + !haveInternalAss.isUndefined() && haveInternalAss.toBool()) { + // ASS is inside Vivy document + if (QJsonValue internalAssSource = json[KeySubDocuments][KeyInternalAssSource]; + !internalAssSource.isUndefined() && internalAssSource.isArray()) { + if (!self->loadSubDocument(internalAssSource, Capabilities::AssAble)) { + throw std::runtime_error("Failed to load ASS sub document"); + } + } + } else if (QJsonValue ass = json[KeySubDocuments][KeySubAss]; !ass.isUndefined()) { + // ASS in its own ASS file + if (!self->loadSubDocument(ass.toString(), Capabilities::AssAble)) + throw std::runtime_error("Failed to load ASS sub document"); + } } void @@ -130,13 +150,12 @@ VivyDocument::getSaveJsonDocumentFile() const subDocumentJson.insert(KeySubVideo, videoDocument->getFilePath()); if (documentType & Capabilities::AssAble) { + subDocumentJson.insert(KeySubAss, assDocument->getFilePath()); + subDocumentJson.insert(KeyHaveInternalAss, assDocument->haveInternalAss()); + // ASS is inside Vivy document - if ((assDocument->getFilePath() == getName())) + if (assDocument->haveInternalAss()) subDocumentJson.insert(KeyInternalAssSource, assDocument->getInternalAss()); - - // ASS is in its own ASS file - else - subDocumentJson.insert(KeySubAss, assDocument->getFilePath()); } json.insert(KeySubDocuments, subDocumentJson); @@ -203,6 +222,26 @@ VivyDocument::loadSubDocument(const QString &subName, VivyDocument::Capabilities return true; } +bool +VivyDocument::loadSubDocument(const QJsonValue &internalAss, + VivyDocument::Capabilities asType) noexcept +{ + logDebug() << "ASS sub-doc: Trying to open file internal ASS"; + + if (asType == Capabilities::AssAble) { + if ([[maybe_unused]] auto doc = assDocument.get()) { + // Here we may want to do some confirmation / cleanup + assDocument.reset(); + } + + assDocument = AssSubDocument::fromInternal(internalAss); + if (assDocument) + addDocumentType(AssAble); + } + + return true; +} + bool VivyDocument::detectDocumentType(const QFileInfo &file, Capabilities *const ableType) noexcept { diff --git a/src/Lib/Document/VivyDocument.hh b/src/Lib/Document/VivyDocument.hh index 37448b56bc833252086505dfb6f850700ab961cb..e2f4d25bb9cf61dafe438881ae73cd37228070f2 100644 --- a/src/Lib/Document/VivyDocument.hh +++ b/src/Lib/Document/VivyDocument.hh @@ -26,6 +26,7 @@ class VivyDocument final : public AbstractDocument { DCL_VIVY_SAVE_KEY(SubAss) DCL_VIVY_SAVE_KEY(SubVideo) DCL_VIVY_SAVE_KEY(InternalAssSource) + DCL_VIVY_SAVE_KEY(HaveInternalAss) DCL_VIVY_SAVE_KEY(DocumentVersion) using LoadFunctionForVersion = @@ -82,6 +83,7 @@ public: void save() override; bool loadSubDocument(const QString &) noexcept; bool loadSubDocument(const QString &, Capabilities) noexcept; + bool loadSubDocument(const QJsonValue &, VivyDocument::Capabilities) noexcept; // Getters std::shared_ptr<AudioSubDocument> getAudioSubDocument() const noexcept; diff --git a/src/UI/MainWindow.cc b/src/UI/MainWindow.cc index a877dcc60bd6118a41e895cb8e170e9e12c227ac..a2bf30110b1979e046f8c7877c37948fc31280da 100644 --- a/src/UI/MainWindow.cc +++ b/src/UI/MainWindow.cc @@ -47,6 +47,7 @@ MainWindow::MainWindow() noexcept DCL_MENU(edit, "&Edit"); DCL_MENU(viewTmp, "&View"); viewMenu = viewTmpMenu; // Save the view menu + DCL_MENU(ass, "&ASS"); DCL_MENU(simulate, "&Simulate"); DCL_MENU(help, "&Help"); @@ -60,6 +61,8 @@ MainWindow::MainWindow() noexcept DCL_ACTION(loadSubDocumentVideo, "&Load video", "Load a vide file as a sub-document", file); DCL_ACTION(loadSubDocumentAss, "&Load ASS", "Load an ASS file as a sub-document", file); + DCL_ACTION(setAssInternal, "&Internal ASS", "Set the ASS subdocument as internal", ass); + DCL_ACTION(openDialogHelp, "&About", "Open the help dialog", help); ACTION_ADD_ICON(newDocument, VIVY_ICON_NEW); @@ -205,6 +208,23 @@ MainWindow::openProperties(int index) noexcept current->openProperties(); } +void +MainWindow::setAssInternal() noexcept +{ + try { + const auto document = dynamic_cast<VivyDocument *>(getCurrentDocument()); + if (document) { + if (auto p = document->getAssSubDocument()) { + p->setInternalAss(true); + } + } + } + + catch (const std::runtime_error &e) { + logError() << "Failed to set ASS as internal: " << e.what(); + } +} + void MainWindow::openDialogHelp() noexcept { diff --git a/src/UI/MainWindow.hh b/src/UI/MainWindow.hh index 690ed2f9b0f3f49b53d5779c7c198bd34a2f49a7..bc59b3ce87f516f6e5079a7cd4c31addcf4028f8 100644 --- a/src/UI/MainWindow.hh +++ b/src/UI/MainWindow.hh @@ -117,6 +117,8 @@ private slots: void saveFileAs() noexcept; void renameFile() noexcept; + void setAssInternal() noexcept; + void openDialogHelp() noexcept; void documentViewActionsChanged() noexcept;