diff --git a/ActionManager.cpp b/ActionManager.cpp index c79e955..36e770f 100644 --- a/ActionManager.cpp +++ b/ActionManager.cpp @@ -33,8 +33,6 @@ void Action::clear() void Action::store(const std::string &label, uint64_t id) { - // TODO use id of item stored - // ignore if locked or if no label is given if (locked_ || label.empty()) return; @@ -71,12 +69,13 @@ void Action::store(const std::string &label, uint64_t id) // debug #ifdef ACTION_DEBUG Log::Info("Action stored %s '%s'", nodename.c_str(), label.c_str()); - // XMLSaveDoc(&xmlDoc_, "/home/bhbn/history.xml"); +// XMLSaveDoc(&xmlDoc_, "/home/bhbn/history.xml"); #endif } void Action::undo() { + // not possible to go to 1 -1 = 0 if (step_ <= 1) return; @@ -87,11 +86,13 @@ void Action::undo() uint64_t id = 0; sessionNode->QueryUnsigned64Attribute("id", &id); + // restore always changes step_ to step_ - 1 restore( step_ - 1, id); } void Action::redo() { + // not possible to go to max_step_ + 1 if (step_ >= max_step_) return; @@ -101,14 +102,29 @@ void Action::redo() uint64_t id = 0; sessionNode->QueryUnsigned64Attribute("id", &id); + // restore always changes step_ to step_ + 1 restore( step_ + 1, id); } void Action::stepTo(uint target) { - // going to target step - restore(target, 0); + // get reasonable target + uint t = CLAMP(target, 1, max_step_); + + // going backward + if ( t < step_ ) { + // go back one step at a time + while (t < step_) + undo(); + } + // step forward + else if ( t > step_ ) { + // go forward one step at a time + while (t > step_) + redo(); + } + // ignore t == step_ } @@ -135,22 +151,31 @@ void Action::restore(uint target, uint64_t id) XMLElement *sessionNode = xmlDoc_.FirstChildElement( nodename.c_str() ); #ifdef ACTION_DEBUG - Log::Info("Restore %s '%s'", nodename.c_str(), sessionNode->Attribute("label")); + Log::Info("Restore %s '%s' ", nodename.c_str(), sessionNode->Attribute("label")); #endif - // sessionsources contains ids of all sources currently in the session - std::list sessionsources = Mixer::manager().session()->getIdList(); + // we operate on the current session + Session *se = Mixer::manager().session(); + if (se == nullptr) + return; + + // sessionsources contains list of ids of all sources currently in the session + std::list sessionsources = se->getIdList(); +// for( auto it = sessionsources.begin(); it != sessionsources.end(); it++) +// Log::Info("sessionsources id %s", std::to_string(*it).c_str()); // load history status: - // - if a source exists, its attributes are updated - // - if a source does not exists (in session), it is created in session - SessionLoader loader( Mixer::manager().session() ); + // - if a source exists, its attributes are updated, and that's all + // - if a source does not exists (in session), it is created in the session + SessionLoader loader( se ); loader.load( sessionNode ); - // loadersources contains ids of all sources generated by loader + // loadersources contains list of ids of all sources generated by loader std::list loadersources = loader.getIdList(); +// for( auto it = loadersources.begin(); it != loadersources.end(); it++) +// Log::Info("loadersources id %s", std::to_string(*it).c_str()); - // remove intersect of both lists (sources were updated) + // remove intersect of both lists (sources were updated by SessionLoader) for( auto lsit = loadersources.begin(); lsit != loadersources.end(); ){ auto ssit = std::find(sessionsources.begin(), sessionsources.end(), (*lsit)); if ( ssit != sessionsources.end() ) { @@ -163,13 +188,25 @@ void Action::restore(uint target, uint64_t id) // remaining ids in list sessionsources : to remove while ( !sessionsources.empty() ){ Source *s = Mixer::manager().findSource( sessionsources.front() ); - Mixer::manager().detach( s ); - Mixer::manager().session()->deleteSource( s ); + if (s!=nullptr) { +#ifdef ACTION_DEBUG + Log::Info("Delete id %s", std::to_string(sessionsources.front() ).c_str()); +#endif + // remove the source from the mixer + Mixer::manager().detach( s ); + // delete source from session + se->deleteSource( s ); + } sessionsources.pop_front(); } // remaining ids in list loadersources : to add while ( !loadersources.empty() ){ - Log::Info("Recreate id %s", std::to_string(loadersources.front() ).c_str()); +#ifdef ACTION_DEBUG + Log::Info("Recreate id %s to %s", std::to_string(id).c_str(), std::to_string(loadersources.front()).c_str()); +#endif + // change the history to match the new id + replaceSourceId(id, loadersources.front()); + // add the source to the mixer Mixer::manager().attach( Mixer::manager().findSource( loadersources.front() ) ); loadersources.pop_front(); } @@ -178,3 +215,32 @@ void Action::restore(uint target, uint64_t id) locked_ = false; } + + +void Action::replaceSourceId(uint64_t previousid, uint64_t newid) +{ + // loop over every session history step + XMLElement* historyNode = xmlDoc_.FirstChildElement("H1"); + for( ; historyNode ; historyNode = historyNode->NextSiblingElement()) + { + // check if this history node references this id + uint64_t id_history_ = 0; + historyNode->QueryUnsigned64Attribute("id", &id_history_); + if ( id_history_ == previousid ) + // change to new id + historyNode->SetAttribute("id", newid); + + // loop over every source in session history + XMLElement* sourceNode = historyNode->FirstChildElement("Source"); + for( ; sourceNode ; sourceNode = sourceNode->NextSiblingElement()) + { + // check if this source node has this id + uint64_t id_source_ = 0; + sourceNode->QueryUnsigned64Attribute("id", &id_source_); + if ( id_source_ == previousid ) + // change to new id + sourceNode->SetAttribute("id", newid); + } + } + +} diff --git a/ActionManager.h b/ActionManager.h index cea3679..dea2fc4 100644 --- a/ActionManager.h +++ b/ActionManager.h @@ -22,7 +22,7 @@ public: return _instance; } - void store(const std::string &label, uint64_t id = -1); + void store(const std::string &label, uint64_t id = 0); void clear(); void undo(); @@ -37,6 +37,7 @@ public: private: void restore(uint target, uint64_t id); + void replaceSourceId(uint64_t previousid, uint64_t newid); tinyxml2::XMLDocument xmlDoc_; uint step_; diff --git a/Mixer.cpp b/Mixer.cpp index a2556be..a370cf2 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -193,7 +193,7 @@ void Mixer::update() if (failedFile != nullptr) { Settings::application.recentImport.remove( failedFile->path() ); } - deleteSource(failure); + deleteSource(failure, false); } // update views @@ -349,7 +349,7 @@ void Mixer::insertSource(Source *s, View::Mode m) attach(s); // new state in history manager - Action::manager().store(std::string("Insert ")+s->name()); + Action::manager().store(s->name() + std::string(" inserted"), s->id()); // if requested to show the source in a given view // (known to work for View::MIXING et TRANSITION: other views untested) @@ -366,12 +366,13 @@ void Mixer::insertSource(Source *s, View::Mode m) } } -void Mixer::deleteSource(Source *s) +void Mixer::deleteSource(Source *s, bool withundo) { if ( s != nullptr ) { // keep name for log std::string name = s->name(); + uint64_t id = s->id(); // remove source Nodes from all views detach(s); @@ -379,8 +380,9 @@ void Mixer::deleteSource(Source *s) // delete source session_->deleteSource(s); - // new state in history manager - Action::manager().store(std::string("Delete ")+name); + // store new state in history manager + if (withundo) + Action::manager().store(name + std::string(" deleted"), id); // log Log::Notify("Source %s deleted.", name.c_str()); diff --git a/Mixer.h b/Mixer.h index fd75edb..da08b06 100644 --- a/Mixer.h +++ b/Mixer.h @@ -45,7 +45,7 @@ public: // operations on sources void addSource (Source *s); - void deleteSource (Source *s); + void deleteSource (Source *s, bool withundo=true); void renameSource (Source *s, const std::string &newname); void attach (Source *s); void detach (Source *s); diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index 3bc8a9b..8a2aefa 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -219,7 +219,7 @@ void SessionVisitor::visit(ImageProcessingShader &n) filter->SetAttribute("nbColors", n.nbColors); filter->SetAttribute("invert", n.invert); filter->SetAttribute("chromadelta", n.chromadelta); - filter->SetAttribute("filterid", n.filterid); + filter->SetAttribute("filter", n.filterid); xmlCurrent_->InsertEndChild(filter); XMLElement *gamma = xmlDoc_->NewElement("gamma"); diff --git a/Timeline.cpp b/Timeline.cpp index 37d273c..88900c7 100644 --- a/Timeline.cpp +++ b/Timeline.cpp @@ -34,6 +34,7 @@ Timeline& Timeline::operator = (const Timeline& b) this->timing_ = b.timing_; this->step_ = b.step_; this->gaps_ = b.gaps_; + this->gaps_array_need_update_ = b.gaps_array_need_update_; memcpy( this->gapsArray_, b.gapsArray_, MAX_TIMELINE_ARRAY * sizeof(float)); memcpy( this->fadingArray_, b.fadingArray_, MAX_TIMELINE_ARRAY * sizeof(float)); }