X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fundo.cc;h=42f7d574ea4030f44f486215901dedba64c0af25;hb=9907d25ea572f008fcb626eb7cc7ffa4cf9e1d82;hp=6db85e6ab34d21518ce5d6c91943dacaf7698232;hpb=d7db3f757fde92126ef9886370ce604992b7e974;p=ardour.git diff --git a/libs/pbd/undo.cc b/libs/pbd/undo.cc index 6db85e6ab3..42f7d574ea 100644 --- a/libs/pbd/undo.cc +++ b/libs/pbd/undo.cc @@ -18,13 +18,12 @@ $Id$ */ -#include #include #include +#include -#include -#include -#include +#include "pbd/undo.h" +#include "pbd/xml++.h" #include @@ -34,19 +33,21 @@ using namespace sigc; UndoTransaction::UndoTransaction () : _clearing(false) { + gettimeofday (&_timestamp, 0); } UndoTransaction::UndoTransaction (const UndoTransaction& rhs) : Command(rhs._name) , _clearing(false) { + _timestamp = rhs._timestamp; clear (); actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end()); } UndoTransaction::~UndoTransaction () { - GoingAway (); + drop_references (); clear (); } @@ -75,11 +76,15 @@ UndoTransaction::operator= (const UndoTransaction& rhs) } void -UndoTransaction::add_command (Command *const action) +UndoTransaction::add_command (Command *const cmd) { - /* catch death */ - new PBD::ProxyShiva (*action, *this, &command_death); - actions.push_back (action); + /* catch death of command (e.g. caused by death of object to + which it refers. command_death() is a normal static function + so there is no need to manage this connection. + */ + + cmd->DropReferences.connect_same_thread (*this, boost::bind (&command_death, this, cmd)); + actions.push_back (cmd); } void @@ -145,18 +150,78 @@ XMLNode &UndoTransaction::get_state() return *node; } +class UndoRedoSignaller { +public: + UndoRedoSignaller (UndoHistory& uh) + : _history (uh) { + _history.BeginUndoRedo(); + } + ~UndoRedoSignaller() { + _history.EndUndoRedo(); + } + +private: + UndoHistory& _history; +}; + UndoHistory::UndoHistory () { _clearing = false; + _depth = 0; +} + +void +UndoHistory::set_depth (uint32_t d) +{ + UndoTransaction* ut; + uint32_t current_depth = UndoList.size(); + + _depth = d; + + if (d > current_depth) { + /* not even transactions to meet request */ + return; + } + + if (_depth > 0) { + + uint32_t cnt = current_depth - d; + + while (cnt--) { + ut = UndoList.front(); + UndoList.pop_front (); + delete ut; + } + } } void UndoHistory::add (UndoTransaction* const ut) { - ut->GoingAway.connect (bind (mem_fun (*this, &UndoHistory::remove), ut)); + uint32_t current_depth = UndoList.size(); + + ut->DropReferences.connect_same_thread (*this, boost::bind (&UndoHistory::remove, this, ut)); + + /* if the current undo history is larger than or equal to the currently + requested depth, then pop off at least 1 element to make space + at the back for new one. + */ + + if ((_depth > 0) && current_depth && (current_depth >= _depth)) { + + uint32_t cnt = 1 + (current_depth - _depth); + + while (cnt--) { + UndoTransaction* ut; + ut = UndoList.front (); + UndoList.pop_front (); + delete ut; + } + } + UndoList.push_back (ut); - /* we are now owners of the transaction */ + /* we are now owners of the transaction and must delete it when finished with it */ Changed (); /* EMIT SIGNAL */ } @@ -180,14 +245,22 @@ UndoHistory::remove (UndoTransaction* const ut) void UndoHistory::undo (unsigned int n) { - while (n--) { - if (UndoList.size() == 0) { - return; + if (n == 0) { + return; + } + + { + UndoRedoSignaller exception_safe_signaller (*this); + + while (n--) { + if (UndoList.size() == 0) { + return; + } + UndoTransaction* ut = UndoList.back (); + UndoList.pop_back (); + ut->undo (); + RedoList.push_back (ut); } - UndoTransaction* ut = UndoList.back (); - UndoList.pop_back (); - ut->undo (); - RedoList.push_back (ut); } Changed (); /* EMIT SIGNAL */ @@ -196,14 +269,22 @@ UndoHistory::undo (unsigned int n) void UndoHistory::redo (unsigned int n) { - while (n--) { - if (RedoList.size() == 0) { - return; + if (n == 0) { + return; + } + + { + UndoRedoSignaller exception_safe_signaller (*this); + + while (n--) { + if (RedoList.size() == 0) { + return; + } + UndoTransaction* ut = RedoList.back (); + RedoList.pop_back (); + ut->redo (); + UndoList.push_back (ut); } - UndoTransaction* ut = RedoList.back (); - RedoList.pop_back (); - ut->redo (); - UndoList.push_back (ut); } Changed (); /* EMIT SIGNAL */ @@ -213,6 +294,9 @@ void UndoHistory::clear_redo () { _clearing = true; + for (std::list::iterator i = RedoList.begin(); i != RedoList.end(); ++i) { + delete *i; + } RedoList.clear (); _clearing = false; @@ -224,6 +308,9 @@ void UndoHistory::clear_undo () { _clearing = true; + for (std::list::iterator i = UndoList.begin(); i != UndoList.end(); ++i) { + delete *i; + } UndoList.clear (); _clearing = false; @@ -240,17 +327,22 @@ UndoHistory::clear () } XMLNode& -UndoHistory::get_state (uint32_t depth) +UndoHistory::get_state (int32_t depth) { XMLNode *node = new XMLNode ("UndoHistory"); if (depth == 0) { + + return (*node); + + } else if (depth < 0) { + /* everything */ for (list::iterator it = UndoList.begin(); it != UndoList.end(); ++it) { node->add_child_nocopy((*it)->get_state()); } - + } else { /* just the last "depth" transactions */ @@ -268,3 +360,5 @@ UndoHistory::get_state (uint32_t depth) return *node; } + +