diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2008-06-02 21:41:35 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2008-06-02 21:41:35 +0000 |
commit | 449aab3c465bbbf66d221fac3d7ea559f1720357 (patch) | |
tree | 6843cc40c88250a132acac701271f1504cd2df04 /libs/pbd/undo.cc | |
parent | 9c0d7d72d70082a54f823cd44c0ccda5da64bb6f (diff) |
rollback to 3428, before the mysterious removal of libs/* at 3431/3432
git-svn-id: svn://localhost/ardour2/branches/3.0@3435 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/pbd/undo.cc')
-rw-r--r-- | libs/pbd/undo.cc | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/libs/pbd/undo.cc b/libs/pbd/undo.cc new file mode 100644 index 0000000000..aeff37cce7 --- /dev/null +++ b/libs/pbd/undo.cc @@ -0,0 +1,293 @@ +/* + Copyright (C) 2001 Brett Viren & Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <iostream> +#include <string> +#include <sstream> + +#include <pbd/undo.h> +#include <pbd/xml++.h> +#include <pbd/shiva.h> + +#include <sigc++/bind.h> + +using namespace std; +using namespace sigc; + +UndoTransaction::UndoTransaction () + : _clearing(false) +{ +} + +UndoTransaction::UndoTransaction (const UndoTransaction& rhs) + : Command(rhs._name) + , _clearing(false) +{ + clear (); + actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end()); +} + +UndoTransaction::~UndoTransaction () +{ + GoingAway (); + clear (); +} + +void +command_death (UndoTransaction* ut, Command* c) +{ + if (ut->clearing()) { + return; + } + + ut->remove_command (c); + + if (ut->empty()) { + delete ut; + } +} + +UndoTransaction& +UndoTransaction::operator= (const UndoTransaction& rhs) +{ + if (this == &rhs) return *this; + _name = rhs._name; + clear (); + actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end()); + return *this; +} + +void +UndoTransaction::add_command (Command *const action) +{ + /* catch death */ + new PBD::ProxyShiva<Command,UndoTransaction> (*action, *this, &command_death); + actions.push_back (action); +} + +void +UndoTransaction::remove_command (Command* const action) +{ + actions.remove (action); +} + +bool +UndoTransaction::empty () const +{ + return actions.empty(); +} + +void +UndoTransaction::clear () +{ + _clearing = true; + for (list<Command*>::iterator i = actions.begin(); i != actions.end(); ++i) { + delete *i; + } + actions.clear (); + _clearing = false; +} + +void +UndoTransaction::operator() () +{ + for (list<Command*>::iterator i = actions.begin(); i != actions.end(); ++i) { + (*(*i))(); + } +} + +void +UndoTransaction::undo () +{ + for (list<Command*>::reverse_iterator i = actions.rbegin(); i != actions.rend(); ++i) { + (*i)->undo(); + } +} + +void +UndoTransaction::redo () +{ + (*this)(); +} + +XMLNode &UndoTransaction::get_state() +{ + XMLNode *node = new XMLNode ("UndoTransaction"); + stringstream ss; + ss << _timestamp.tv_sec; + node->add_property("tv_sec", ss.str()); + ss.str(""); + ss << _timestamp.tv_usec; + node->add_property("tv_usec", ss.str()); + node->add_property("name", _name); + + list<Command*>::iterator it; + for (it=actions.begin(); it!=actions.end(); it++) + node->add_child_nocopy((*it)->get_state()); + + return *node; +} + +UndoHistory::UndoHistory () +{ + _clearing = false; + _depth = 0; +} + +void +UndoHistory::set_depth (int32_t d) +{ + _depth = d; + + while (_depth > 0 && UndoList.size() > (uint32_t) _depth) { + UndoList.pop_front (); + } +} + +void +UndoHistory::add (UndoTransaction* const ut) +{ + ut->GoingAway.connect (bind (mem_fun (*this, &UndoHistory::remove), ut)); + + while (_depth > 0 && UndoList.size() > (uint32_t) _depth) { + UndoList.pop_front (); + } + + UndoList.push_back (ut); + + /* we are now owners of the transaction */ + + Changed (); /* EMIT SIGNAL */ +} + +void +UndoHistory::remove (UndoTransaction* const ut) +{ + if (_clearing) { + return; + } + + UndoList.remove (ut); + RedoList.remove (ut); + + Changed (); /* EMIT SIGNAL */ +} + +/** Undo some transactions. + * @param n Number of transactions to undo. + */ +void +UndoHistory::undo (unsigned int n) +{ + while (n--) { + if (UndoList.size() == 0) { + return; + } + UndoTransaction* ut = UndoList.back (); + UndoList.pop_back (); + ut->undo (); + RedoList.push_back (ut); + } + + Changed (); /* EMIT SIGNAL */ +} + +void +UndoHistory::redo (unsigned int n) +{ + while (n--) { + if (RedoList.size() == 0) { + return; + } + UndoTransaction* ut = RedoList.back (); + RedoList.pop_back (); + ut->redo (); + UndoList.push_back (ut); + } + + Changed (); /* EMIT SIGNAL */ +} + +void +UndoHistory::clear_redo () +{ + _clearing = true; + RedoList.clear (); + _clearing = false; + + Changed (); /* EMIT SIGNAL */ + +} + +void +UndoHistory::clear_undo () +{ + _clearing = true; + UndoList.clear (); + _clearing = false; + + Changed (); /* EMIT SIGNAL */ +} + +void +UndoHistory::clear () +{ + clear_undo (); + clear_redo (); + + Changed (); /* EMIT SIGNAL */ +} + +XMLNode& +UndoHistory::get_state (int32_t depth) +{ + XMLNode *node = new XMLNode ("UndoHistory"); + + if (depth == 0) { + + return (*node); + + } else if (depth < 0) { + + /* everything */ + + for (list<UndoTransaction*>::iterator it = UndoList.begin(); it != UndoList.end(); ++it) { + node->add_child_nocopy((*it)->get_state()); + } + + } else { + + /* just the last "depth" transactions */ + + list<UndoTransaction*> in_order; + + for (list<UndoTransaction*>::reverse_iterator it = UndoList.rbegin(); it != UndoList.rend() && depth; ++it, depth--) { + in_order.push_front (*it); + } + + for (list<UndoTransaction*>::iterator it = in_order.begin(); it != in_order.end(); it++) { + node->add_child_nocopy((*it)->get_state()); + } + } + + return *node; +} + + |