r132@gandalf: fugalh | 2006-06-29 12:45:16 -0600
Coding for undo/redo starts in earnest. Paul and I decided to go with a standard gang of four Command pattern, with serialization. This overcomes the terrible difficulties we were having with static type checking and the sigc++ approach. I'm adding the requirement that each command support undo, simplifying undo/redo. NOTE that an important fallout here is that Command::operator()() is the opposite of the old UndoAction::operator()(), i.e. Command::operator()() is execute/redo, and Command::undo() is undo. This commit is a reworking of the infrastructure, and won't compile until creating Command subclasses for the various commands being performed. That is primarily where you find get_memento and/or calls to add_(undo|redo.*). git-svn-id: svn://localhost/ardour2/branches/undo@655 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
37
libs/pbd3/pbd/command.h
Normal file
37
libs/pbd3/pbd/command.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright (C) 2006 Hans Fugal & 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: /local/undo/libs/pbd3/pbd/undo.h 80 2006-06-22T22:37:01.079855Z fugalh $
|
||||
*/
|
||||
|
||||
#ifndef __lib_pbd_undo_h__
|
||||
#define __lib_pbd_undo_h__
|
||||
|
||||
#include <pbd/serializable.h>
|
||||
|
||||
class Command : public Serializable
|
||||
{
|
||||
public:
|
||||
virtual ~Command();
|
||||
virtual void operator() () = 0;
|
||||
virtual void undo() = 0;
|
||||
virtual void redo() { (*this)(); }
|
||||
protected:
|
||||
Command();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -26,7 +26,7 @@
|
||||
class Serializable
|
||||
{
|
||||
public:
|
||||
XMLNode &serialize();
|
||||
virtual XMLNode &serialize() = 0;
|
||||
};
|
||||
|
||||
#endif // __lib_pbd_serializable_h__
|
||||
|
||||
@@ -27,14 +27,14 @@
|
||||
#include <sigc++/slot.h>
|
||||
#include <sigc++/bind.h>
|
||||
#include <sys/time.h>
|
||||
#include <pbd/undo_command.h>
|
||||
#include <pbd/command.h>
|
||||
|
||||
using std::string;
|
||||
using std::list;
|
||||
|
||||
typedef sigc::slot<void> UndoAction;
|
||||
typedef Command UndoAction;
|
||||
|
||||
class UndoTransaction
|
||||
class UndoTransaction : public Command
|
||||
{
|
||||
public:
|
||||
UndoTransaction ();
|
||||
@@ -43,12 +43,10 @@ class UndoTransaction
|
||||
|
||||
void clear ();
|
||||
|
||||
void add_undo (const UndoAction&);
|
||||
void add_redo (const UndoAction&);
|
||||
void add_redo_no_execute (const UndoAction&);
|
||||
void add_command (const UndoAction&);
|
||||
|
||||
void operator() ();
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
void set_name (const string& str) {
|
||||
_name = str;
|
||||
@@ -64,8 +62,7 @@ class UndoTransaction
|
||||
}
|
||||
|
||||
private:
|
||||
list<UndoAction> redo_actions;
|
||||
list<UndoAction> undo_actions;
|
||||
list<UndoAction> actions;
|
||||
struct timeval _timestamp;
|
||||
string _name;
|
||||
};
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2006 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: /local/undo/libs/pbd3/pbd/undo.h 59 2006-06-15T18:16:20.960977Z fugalh $
|
||||
*/
|
||||
|
||||
#ifndef __lib_pbd_undo_command_h__
|
||||
#define __lib_pbd_undo_command_h__
|
||||
|
||||
#include <sigc++/slot.h>
|
||||
#include <sigc++/bind.h>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <pbd/serializable.h>
|
||||
|
||||
using sigc::nil;
|
||||
using sigc::slot;
|
||||
using sigc::bind;
|
||||
using sigc::mem_fun;
|
||||
using std::list;
|
||||
using std::string;
|
||||
|
||||
|
||||
/* One of the joys of templates is that you have to do everything right here
|
||||
* in the header file; you can't split this to make undo_command.cc */
|
||||
|
||||
template <class T_obj, class T1=nil, class T2=nil, class T3=nil, class T4=nil>
|
||||
class UndoCommand
|
||||
{
|
||||
public:
|
||||
/* It only makes sense to use the constructor corresponding to the
|
||||
* template given. e.g.
|
||||
*
|
||||
* UndoCommand<Foo> cmd(id, key, foo_instance);
|
||||
*/
|
||||
UndoCommand(T_obj &object, string key)
|
||||
: _obj(object), _key(key)
|
||||
{
|
||||
_slot = mem_fun( _obj, get_method(_key) );
|
||||
}
|
||||
UndoCommand(T_obj &object, string key, T1 &arg1)
|
||||
: _obj(object), _key(key)
|
||||
{
|
||||
_slot = bind( mem_fun( _obj, get_method(_key) ),
|
||||
arg1);
|
||||
_args.push_back(&arg1);
|
||||
}
|
||||
UndoCommand(T_obj &object, string key, T1 &arg1, T2 &arg2)
|
||||
: _obj(object), _key(key)
|
||||
{
|
||||
_slot = bind( mem_fun( _obj, get_method(_key) ),
|
||||
arg1, arg2);
|
||||
_args.push_back(&arg1);
|
||||
_args.push_back(&arg2);
|
||||
}
|
||||
UndoCommand(T_obj &object, string key, T1 &arg1, T2 &arg2, T3 &arg3)
|
||||
: _obj(object), _key(key)
|
||||
{
|
||||
_slot = bind( mem_fun( _obj, get_method(_key) ),
|
||||
arg1, arg2, arg3);
|
||||
_args.push_back(&arg1);
|
||||
_args.push_back(&arg2);
|
||||
_args.push_back(&arg3);
|
||||
}
|
||||
UndoCommand(T_obj &object, string key, T1 &arg1, T2 &arg2, T3 &arg3, T4 &arg4)
|
||||
: _obj(object), _key(key)
|
||||
{
|
||||
_slot = bind( mem_fun( _obj, get_method(_key) ),
|
||||
arg1, arg2, arg4);
|
||||
_args.push_back(&arg1);
|
||||
_args.push_back(&arg2);
|
||||
_args.push_back(&arg3);
|
||||
_args.push_back(&arg4);
|
||||
}
|
||||
|
||||
void operator() () { return _slot(); }
|
||||
|
||||
XMLNode &serialize();
|
||||
protected:
|
||||
template <class T_method> T_method &get_method(string);
|
||||
T_obj &_obj;
|
||||
string _key;
|
||||
slot<void> _slot;
|
||||
|
||||
// Note that arguments must be instances of Serializable or this will
|
||||
// rightly cause a compiler error when compiling the constructor.
|
||||
list<Serializable*> _args;
|
||||
};
|
||||
|
||||
#endif // __lib_pbd_undo_command_h__
|
||||
@@ -33,8 +33,7 @@ UndoTransaction::UndoTransaction (const UndoTransaction& rhs)
|
||||
{
|
||||
_name = rhs._name;
|
||||
clear ();
|
||||
undo_actions.insert(undo_actions.end(),rhs.undo_actions.begin(),rhs.undo_actions.end());
|
||||
redo_actions.insert(redo_actions.end(),rhs.redo_actions.begin(),rhs.redo_actions.end());
|
||||
actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end());
|
||||
}
|
||||
|
||||
UndoTransaction&
|
||||
@@ -43,43 +42,36 @@ UndoTransaction::operator= (const UndoTransaction& rhs)
|
||||
if (this == &rhs) return *this;
|
||||
_name = rhs._name;
|
||||
clear ();
|
||||
undo_actions.insert(undo_actions.end(),rhs.undo_actions.begin(),rhs.undo_actions.end());
|
||||
redo_actions.insert(redo_actions.end(),rhs.redo_actions.begin(),rhs.redo_actions.end());
|
||||
actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
UndoTransaction::add_undo (const UndoAction& action)
|
||||
UndoTransaction::add_command (const UndoAction& action)
|
||||
{
|
||||
undo_actions.push_back (action);
|
||||
}
|
||||
|
||||
void
|
||||
UndoTransaction::add_redo (const UndoAction& action)
|
||||
{
|
||||
redo_actions.push_back (action);
|
||||
redo_actions.back()(); // operator()
|
||||
}
|
||||
|
||||
void
|
||||
UndoTransaction::add_redo_no_execute (const UndoAction& action)
|
||||
{
|
||||
redo_actions.push_back (action);
|
||||
actions.push_back (action);
|
||||
}
|
||||
|
||||
void
|
||||
UndoTransaction::clear ()
|
||||
{
|
||||
undo_actions.clear ();
|
||||
redo_actions.clear ();
|
||||
actions.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
UndoTransaction::operator() ()
|
||||
{
|
||||
for (list<UndoAction>::iterator i = actions.begin(); i != actions.end(); ++i) {
|
||||
(*i)();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UndoTransaction::undo ()
|
||||
{
|
||||
cerr << "Undo " << _name << endl;
|
||||
for (list<UndoAction>::reverse_iterator i = undo_actions.rbegin(); i != undo_actions.rend(); ++i) {
|
||||
(*i)();
|
||||
for (list<UndoAction>::reverse_iterator i = actions.rbegin(); i != actions.rend(); ++i) {
|
||||
i->undo();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,9 +79,7 @@ void
|
||||
UndoTransaction::redo ()
|
||||
{
|
||||
cerr << "Redo " << _name << endl;
|
||||
for (list<UndoAction>::iterator i = redo_actions.begin(); i != redo_actions.end(); ++i) {
|
||||
(*i)();
|
||||
}
|
||||
(*this)();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -119,9 +109,9 @@ UndoHistory::redo (unsigned int n)
|
||||
if (RedoList.size() == 0) {
|
||||
return;
|
||||
}
|
||||
UndoTransaction trans = RedoList.back ();
|
||||
UndoTransaction ut = RedoList.back ();
|
||||
RedoList.pop_back ();
|
||||
trans.redo ();
|
||||
ut.redo ();
|
||||
UndoList.push_back (trans);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user