From 68f9f86266cfcc755f11f85008faabd0ad20ffe7 Mon Sep 17 00:00:00 2001
From: Elliu <elliu@hashi.re>
Date: Sun, 24 Jul 2022 12:56:48 +0200
Subject: [PATCH] WIP: allow for internal ASS saving and loading

Ass factory constructor from internal still needs to be really
implemented
---
 src/Lib/Ass/AssFactory.cc                     | 13 +++++
 src/Lib/Ass/AssFactory.hh                     |  1 +
 src/Lib/Document/CRTPSubDocument.hh           | 23 +++++++++
 .../CRTPSubDocument/AssSubDocument.cc         | 28 +++++++++++
 src/Lib/Document/VivyDocument.cc              | 49 +++++++++++++++++--
 src/Lib/Document/VivyDocument.hh              |  2 +
 src/UI/MainWindow.cc                          | 20 ++++++++
 src/UI/MainWindow.hh                          |  2 +
 8 files changed, 133 insertions(+), 5 deletions(-)

diff --git a/src/Lib/Ass/AssFactory.cc b/src/Lib/Ass/AssFactory.cc
index 334de5b8..7bd08bfe 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 8e181288..544806af 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 7aea6cf7..a32869f9 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 9f55a6f3..a1266bf8 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 baf0113e..8dc4064c 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 37448b56..e2f4d25b 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 a877dcc6..a2bf3011 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 690ed2f9..bc59b3ce 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;
-- 
GitLab