Better implementation of SessionSnapshots saving

This commit is contained in:
Bruno
2021-04-18 18:22:21 +02:00
parent d68987be0f
commit a50a6e129c
8 changed files with 67 additions and 93 deletions

View File

@@ -1,6 +1,5 @@
#include <string>
#include <algorithm>
#include <sstream>
#include "Log.h"
#include "View.h"
@@ -28,7 +27,7 @@ Action::Action(): history_step_(0), history_max_step_(0)
{
}
void Action::init(const std::string &xml)
void Action::init()
{
// clean the history
history_doc_.Clear();
@@ -36,28 +35,6 @@ void Action::init(const std::string &xml)
history_max_step_ = 0;
// start fresh
store("Session start");
// clean the snapshots
snapshots_doc_.Clear();
snapshots_.clear();
if ( !xml.empty() ) {
if ( XMLResultError( snapshots_doc_.Parse( xml.c_str() ) ))
Log::Info("Failed to load snapshots");
else
{
const XMLElement* N = snapshots_doc_.RootElement();
for( ; N ; N=N->NextSiblingElement()) {
char c;
u_int64_t id = 0;
std::istringstream nodename( N->Name() );
nodename >> c >> id;
snapshots_.push_back(id);
}
}
}
}
void Action::store(const std::string &label)
@@ -173,48 +150,47 @@ void Action::snapshot(const std::string &label)
if (locked_ || label.empty())
return;
// get session to operate on
Session *se = Mixer::manager().session();
// create snapshot id
u_int64_t id = GlmToolkit::uniqueId();
snapshots_.push_back(id);
se->snapshots()->keys_.push_back(id);
// create snapshot node
XMLElement *sessionNode = snapshots_doc_.NewElement( SNAPSHOT_NODE(id) );
snapshots_doc_.InsertEndChild(sessionNode);
XMLElement *sessionNode = se->snapshots()->xmlDoc_->NewElement( SNAPSHOT_NODE(id) );
se->snapshots()->xmlDoc_->InsertEndChild(sessionNode);
// label describes the snapshot
sessionNode->SetAttribute("label", label.c_str());
// get session to operate on
Session *se = Mixer::manager().session();
// save all sources using source visitor
SessionVisitor sv(&snapshots_doc_, sessionNode);
SessionVisitor sv(se->snapshots()->xmlDoc_, sessionNode);
for (auto iter = se->begin(); iter != se->end(); ++iter, sv.setRoot(sessionNode) )
(*iter)->accept(sv);
// TODO: copy action history instead?
// TODO: copy current action history instead?
// debug
#ifdef ACTION_DEBUG
Log::Info("Snapshot stored %d '%s'", id, label.c_str());
// XMLSaveDoc(&xmlDoc_, "/home/bhbn/history.xml");
#endif
}
const char *Action::snapshotsDescription()
std::list<uint64_t> Action::snapshots() const
{
// get compact string
XMLPrinter xmlPrint;
snapshots_doc_.Print( &xmlPrint );
return xmlPrint.CStr();
Session *se = Mixer::manager().session();
return se->snapshots()->keys_;
}
std::string Action::label(uint64_t snapshotid) const
{
std::string l = "";
const XMLElement *sessionNode = snapshots_doc_.FirstChildElement( SNAPSHOT_NODE(snapshotid) );
// get snapshot node of target in current session
Session *se = Mixer::manager().session();
const XMLElement *sessionNode = se->snapshots()->xmlDoc_->FirstChildElement( SNAPSHOT_NODE(snapshotid) );
if (sessionNode) {
l = sessionNode->Attribute("label");
@@ -224,8 +200,9 @@ std::string Action::label(uint64_t snapshotid) const
void Action::setLabel (uint64_t snapshotid, const std::string &label)
{
// get history node of target
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( SNAPSHOT_NODE(snapshotid) );
// get snapshot node of target in current session
Session *se = Mixer::manager().session();
XMLElement *sessionNode = se->snapshots()->xmlDoc_->FirstChildElement( SNAPSHOT_NODE(snapshotid) );
if (sessionNode) {
sessionNode->SetAttribute("label", label.c_str());
@@ -234,12 +211,13 @@ void Action::setLabel (uint64_t snapshotid, const std::string &label)
void Action::remove(uint64_t snapshotid)
{
// get history node of target
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( SNAPSHOT_NODE(snapshotid) );
// get snapshot node of target in current session
Session *se = Mixer::manager().session();
XMLElement *sessionNode = se->snapshots()->xmlDoc_->FirstChildElement( SNAPSHOT_NODE(snapshotid) );
if (sessionNode) {
snapshots_doc_.DeleteChild( sessionNode );
snapshots_.remove(snapshotid);
se->snapshots()->xmlDoc_->DeleteChild( sessionNode );
se->snapshots()->keys_.remove(snapshotid);
}
}
@@ -248,8 +226,9 @@ void Action::restore(uint64_t snapshotid)
// lock
locked_ = true;
// get history node of target
XMLElement *sessionNode = snapshots_doc_.FirstChildElement( SNAPSHOT_NODE(snapshotid) );
// get snapshot node of target in current session
Session *se = Mixer::manager().session();
XMLElement *sessionNode = se->snapshots()->xmlDoc_->FirstChildElement( SNAPSHOT_NODE(snapshotid) );
if (sessionNode) {
// actually restore
@@ -260,6 +239,5 @@ void Action::restore(uint64_t snapshotid)
locked_ = false;
store("Snapshot " + label(snapshotid));
}

View File

@@ -23,7 +23,7 @@ public:
static Action _instance;
return _instance;
}
void init(const std::string &xml = "");
void init();
// UNDO History
void store(const std::string &label);
@@ -38,17 +38,13 @@ public:
// Snapshots
void snapshot(const std::string &label);
inline std::list<uint64_t> snapshots() const { return snapshots_; }
std::list<uint64_t> snapshots() const;
void restore(uint64_t snapshotid);
void remove (uint64_t snapshotid);
std::string label(uint64_t snapshotid) const;
void setLabel (uint64_t snapshotid, const std::string &label);
const char *snapshotsDescription();
// inline const tinyxml2::XMLElement *snapshotsRoot() const { return snapshots_doc_.RootElement(); }
private:
tinyxml2::XMLDocument history_doc_;
@@ -57,9 +53,6 @@ private:
std::atomic<bool> locked_;
void restore(uint target);
tinyxml2::XMLDocument snapshots_doc_;
std::list<uint64_t> snapshots_;
};

View File

@@ -1164,7 +1164,7 @@ void Mixer::swap()
back_session_ = nullptr;
// reset History manager
Action::manager().init( session_->snapshots() );
Action::manager().init();
// notification
Log::Notify("Session %s loaded. %d source(s) created.", session_->filename().c_str(), session_->numSource());

View File

@@ -17,7 +17,7 @@ SessionNote::SessionNote(const std::string &t, bool l, int s): label(std::to_str
{
}
Session::Session() : active_(true), filename_(""), failedSource_(nullptr), snapshots_(""), fading_target_(0.f)
Session::Session() : active_(true), filename_(""), failedSource_(nullptr), fading_target_(0.f)
{
config_[View::RENDERING] = new Group;
config_[View::RENDERING]->scale_ = glm::vec3(0.f);
@@ -37,6 +37,8 @@ Session::Session() : active_(true), filename_(""), failedSource_(nullptr), snaps
config_[View::TEXTURE] = new Group;
config_[View::TEXTURE]->scale_ = Settings::application.views[View::TEXTURE].default_scale;
config_[View::TEXTURE]->translation_ = Settings::application.views[View::TEXTURE].default_translation;
snapshots_.xmlDoc_ = new tinyxml2::XMLDocument;
}
@@ -60,6 +62,9 @@ Session::~Session()
delete config_[View::LAYER];
delete config_[View::MIXING];
delete config_[View::TEXTURE];
snapshots_.keys_.clear();
delete snapshots_.xmlDoc_;
}
void Session::setActive (bool on)
@@ -126,7 +131,6 @@ void Session::update(float dt)
}
SourceList::iterator Session::addSource(Source *s)
{
// lock before change
@@ -178,7 +182,6 @@ SourceList::iterator Session::deleteSource(Source *s)
return its;
}
void Session::removeSource(Source *s)
{
// lock before change
@@ -201,7 +204,6 @@ void Session::removeSource(Source *s)
access_.unlock();
}
Source *Session::popSource()
{
Source *s = nullptr;
@@ -385,7 +387,6 @@ void Session::unlink (SourceList sources)
}
}
void Session::addNote(SessionNote note)
{
notes_.push_back( note );
@@ -419,7 +420,6 @@ std::list<SourceList> Session::getMixingGroups () const
return lmg;
}
std::list<MixingGroup *>::iterator Session::deleteMixingGroup (std::list<MixingGroup *>::iterator g)
{
if (g != mixing_groups_.end()) {
@@ -449,7 +449,6 @@ void Session::unlock()
access_.unlock();
}
void Session::validate (SourceList &sources)
{
// verify that all sources given are valid in the sesion

View File

@@ -6,6 +6,9 @@
#include "SourceList.h"
#include "RenderView.h"
namespace tinyxml2 {
class XMLDocument;
}
class FrameGrabber;
class MixingGroup;
@@ -21,16 +24,12 @@ struct SessionNote
SessionNote(const std::string &t = "", bool l = false, int s = 0);
};
struct SessionSnapshot
{
uint64_t id;
std::string label;
std::string xml;
struct SessionSnapshots {
SessionSnapshot(const std::string &l, const std::string &desc);
tinyxml2::XMLDocument *xmlDoc_;
std::list<uint64_t> keys_;
};
class Session
{
public:
@@ -120,8 +119,7 @@ public:
std::list<MixingGroup *>::iterator deleteMixingGroup (std::list<MixingGroup *>::iterator g);
// snapshots
void setSnapshots (const std::string &xml) { snapshots_ = xml; }
std::string snapshots () const { return snapshots_; }
SessionSnapshots * const snapshots () { return &snapshots_; }
// lock and unlock access (e.g. while saving)
void lock ();
@@ -137,7 +135,7 @@ protected:
std::list<SessionNote> notes_;
std::list<MixingGroup *> mixing_groups_;
std::map<View::Mode, Group*> config_;
std::string snapshots_;
SessionSnapshots snapshots_;
float fading_target_;
std::mutex access_;
};

View File

@@ -1,4 +1,4 @@
#include "SessionCreator.h"
#include <sstream>
#include "Log.h"
#include "defines.h"
@@ -18,10 +18,10 @@
#include "MediaPlayer.h"
#include "SystemToolkit.h"
#include <tinyxml2.h>
#include "tinyxml2Toolkit.h"
using namespace tinyxml2;
#include "SessionCreator.h"
std::string SessionCreator::info(const std::string& filename)
{
@@ -127,8 +127,17 @@ void SessionCreator::loadSnapshots(XMLElement *snapshotsNode)
{
if (snapshotsNode != nullptr && session_ != nullptr) {
std::string text = std::string ( snapshotsNode->GetText() );
session_->setSnapshots( text );
const XMLElement* N = snapshotsNode->FirstChildElement();
for( ; N ; N = N->NextSiblingElement()) {
char c;
u_int64_t id = 0;
std::istringstream nodename( N->Name() );
nodename >> c >> id;
session_->snapshots()->keys_.push_back(id);
session_->snapshots()->xmlDoc_->InsertEndChild( N->DeepClone(session_->snapshots()->xmlDoc_) );
}
}
}
@@ -406,7 +415,7 @@ Source *SessionLoader::createSource(tinyxml2::XMLElement *sourceNode, Mode mode)
}
bool SessionLoader::isClipboard(std::string clipboard)
bool SessionLoader::isClipboard(const std::string &clipboard)
{
if (clipboard.size() > 6 && clipboard.substr(0, 6) == "<" APP_NAME )
return true;
@@ -414,7 +423,7 @@ bool SessionLoader::isClipboard(std::string clipboard)
return false;
}
tinyxml2::XMLElement* SessionLoader::firstSourceElement(std::string clipboard, XMLDocument &xmlDoc)
tinyxml2::XMLElement* SessionLoader::firstSourceElement(const std::string &clipboard, XMLDocument &xmlDoc)
{
tinyxml2::XMLElement* sourceNode = nullptr;
@@ -435,7 +444,7 @@ tinyxml2::XMLElement* SessionLoader::firstSourceElement(std::string clipboard, X
return sourceNode;
}
void SessionLoader::applyImageProcessing(const Source &s, std::string clipboard)
void SessionLoader::applyImageProcessing(const Source &s, const std::string &clipboard)
{
if ( !isClipboard(clipboard) )
return;

View File

@@ -29,9 +29,9 @@ public:
} Mode;
Source *createSource(tinyxml2::XMLElement *sourceNode, Mode mode = CLONE);
static bool isClipboard(std::string clipboard);
static tinyxml2::XMLElement* firstSourceElement(std::string clipboard, tinyxml2::XMLDocument &xmlDoc);
static void applyImageProcessing(const Source &s, std::string clipboard);
static bool isClipboard(const std::string &clipboard);
static tinyxml2::XMLElement* firstSourceElement(const std::string &clipboard, tinyxml2::XMLDocument &xmlDoc);
static void applyImageProcessing(const Source &s, const std::string &clipboard);
//TODO static void applyMask(const Source &s, std::string clipboard);
// Elements of Scene

View File

@@ -76,12 +76,9 @@ bool SessionVisitor::saveSession(const std::string& filename, Session *session)
// 3. snapshots
XMLElement *snapshots = xmlDoc.NewElement("Snapshots");
// const XMLElement* N = Action::manager().snapshotsRoot();
// for( ; N ; N=N->NextSiblingElement())
// snapshots->InsertEndChild( N->DeepClone( &xmlDoc ));
XMLText *desc = xmlDoc.NewText( Action::manager().snapshotsDescription() );
snapshots->InsertEndChild( desc );
const XMLElement* N = session->snapshots()->xmlDoc_->FirstChildElement();
for( ; N ; N=N->NextSiblingElement())
snapshots->InsertEndChild( N->DeepClone( &xmlDoc ));
xmlDoc.InsertEndChild(snapshots);
// 4. optional notes