diff --git a/ActionManager.cpp b/ActionManager.cpp index b83bc87..b53283e 100644 --- a/ActionManager.cpp +++ b/ActionManager.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "Log.h" #include "View.h" @@ -444,3 +445,68 @@ void Action::interpolate(float val, uint64_t snapshotid) } + + +// static multithreaded version saving +static void saveSnapshot(const std::string& filename, tinyxml2::XMLElement *snapshot_node) +{ + if (!snapshot_node){ + Log::Warning("Invalid version.", filename.c_str()); + return; + } + const char *l = snapshot_node->Attribute("label"); + if (!l) { + Log::Warning("Invalid version.", filename.c_str()); + return; + } + + // load the file: is it a session? + tinyxml2::XMLDocument xmlDoc; + XMLError eResult = xmlDoc.LoadFile(filename.c_str()); + if ( XMLResultError(eResult)){ + Log::Warning("%s could not be openned for re-export.", filename.c_str()); + return; + } + XMLElement *header = xmlDoc.FirstChildElement(APP_NAME); + if (header == nullptr) { + Log::Warning("%s is not a %s session file.", filename.c_str(), APP_NAME); + return; + } + + // remove all snapshots + XMLElement* snapshotNode = xmlDoc.FirstChildElement("Snapshots"); + xmlDoc.DeleteChild(snapshotNode); + + // swap "Session" node with version_node + XMLElement *sessionNode = xmlDoc.FirstChildElement("Session"); + xmlDoc.DeleteChild(sessionNode); + sessionNode = snapshot_node->DeepClone(&xmlDoc)->ToElement(); + sessionNode->SetName("Session"); + xmlDoc.InsertEndChild(sessionNode); + + // we got a session, set a new export filename + std::string newfilename = filename; + newfilename.insert(filename.size()-4, "_" + std::string(l)); + + // save new file to disk + if ( XMLSaveDoc(&xmlDoc, newfilename) ) + Log::Notify("Version exported to %s.", newfilename.c_str()); + else + // error + Log::Warning("Failed to export Session file %s.", newfilename.c_str()); +} + +void Action::saveas(const std::string& filename, uint64_t snapshotid) +{ + // ignore if locked or if no label is given + if (locked_) + return; + + if (snapshotid > 0) + open(snapshotid); + + if (snapshot_node_) { + // launch a thread to save the session + std::thread (saveSnapshot, filename, snapshot_node_).detach(); + } +} diff --git a/ActionManager.h b/ActionManager.h index 4ffd49e..d3c5bad 100644 --- a/ActionManager.h +++ b/ActionManager.h @@ -44,10 +44,11 @@ public: std::list snapshots () const; uint64_t currentSnapshot () const { return snapshot_id_; } - void open (uint64_t snapshotid); + void open (uint64_t snapshotid); void replace (uint64_t snapshotid = 0); void restore (uint64_t snapshotid = 0); void remove (uint64_t snapshotid = 0); + void saveas (const std::string& filename, uint64_t snapshotid = 0); std::string label (uint64_t snapshotid) const; std::string date (uint64_t snapshotid) const; diff --git a/Mixer.h b/Mixer.h index 82d0afe..126759a 100644 --- a/Mixer.h +++ b/Mixer.h @@ -115,6 +115,8 @@ public: // create sources if clipboard contains well-formed xml text void paste (const std::string& clipboard); + + // version and undo management void restore(tinyxml2::XMLElement *sessionNode); protected: diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index 4f2af1e..8cd44f4 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -4830,6 +4830,13 @@ void Navigator::RenderMainPannelVimix() Action::manager().restore(); if (ImGui::Selectable( ICON_FA_CODE_BRANCH "- Remove", false, 0, size )) Action::manager().remove(); + // export option if possible + std::string filename = Mixer::manager().session()->filename(); + if (filename.size()>0) { + if (ImGui::Selectable( ICON_FA_FILE_DOWNLOAD " Export", false, 0, size )) { + Action::manager().saveas(filename); + } + } ImGui::EndPopup(); } else