r132@gandalf: fugalh | 2006-06-29 12:45:16 -0600
authorHans Fugal <hans@fugal.net>
Thu, 29 Jun 2006 18:49:03 +0000 (18:49 +0000)
committerHans Fugal <hans@fugal.net>
Thu, 29 Jun 2006 18:49:03 +0000 (18:49 +0000)
 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

libs/pbd3/pbd/command.h [new file with mode: 0644]
libs/pbd3/pbd/serializable.h
libs/pbd3/pbd/undo.h
libs/pbd3/pbd/undo_command.h [deleted file]
libs/pbd3/undo.cc

diff --git a/libs/pbd3/pbd/command.h b/libs/pbd3/pbd/command.h
new file mode 100644 (file)
index 0000000..b154c6b
--- /dev/null
@@ -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
index 8032f0038a639ded23eef14f50432182368fc316..c0948b993370e82b08b40a5d95be45ae31e9845d 100644 (file)
@@ -26,7 +26,7 @@
 class Serializable 
 {
 public:
-    XMLNode &serialize();
+    virtual XMLNode &serialize() = 0;
 };
 
 #endif // __lib_pbd_serializable_h__
index d2ad6088cdc72b7c07e033c13c344028febb6b8f..b97c8d9249307c4a94dedd66e8b13abe8157c269 100644 (file)
 #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;
 };
diff --git a/libs/pbd3/pbd/undo_command.h b/libs/pbd3/pbd/undo_command.h
deleted file mode 100644 (file)
index 1c9cac7..0000000
+++ /dev/null
@@ -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__
index 0aac58effc51c2b3705ead608e52fa73ffffac61..0a09ffd1e784edfd92cbd8df6348a9535e10af79 100644 (file)
@@ -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);
+       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)
+UndoTransaction::clear ()
 {
-       redo_actions.push_back (action);
+       actions.clear ();
 }
 
 void
-UndoTransaction::clear ()
+UndoTransaction::operator() ()
 {
-       undo_actions.clear ();
-       redo_actions.clear ();
+       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);
        }
 }