Add a couple of visibility specifiers that were missing
[ardour.git] / libs / pbd / pbd / sequence_property.h
index 5b37d7a0fc6ef3af330c76589391f47df9f37b86..e105e82e47c01ba7c61529ff024f892a82661e0d 100644 (file)
 
 #include <boost/function.hpp>
 
+#include "pbd/libpbd_visibility.h"
 #include "pbd/convert.h"
 #include "pbd/id.h"
 #include "pbd/property_basics.h"
 #include "pbd/property_list.h"
+#include "pbd/stateful_diff_command.h"
+#include "pbd/error.h"
 
 namespace PBD {
 
@@ -41,7 +44,7 @@ namespace PBD {
  *  any change.
  */
 template<typename Container>
-class SequenceProperty : public PropertyBase
+class /*LIBPBD_API*/ SequenceProperty : public PropertyBase
 {
   public:
         typedef std::set<typename Container::value_type> ChangeContainer;
@@ -80,8 +83,6 @@ class SequenceProperty : public PropertyBase
        SequenceProperty (PropertyID id, const boost::function<void(const ChangeRecord&)>& update)
                 : PropertyBase (id), _update_callback (update) {}
 
-       virtual typename Container::value_type lookup_id (const PBD::ID&) const = 0;
-
         void invert () {
                _changes.removed.swap (_changes.added);
         }
@@ -94,21 +95,28 @@ class SequenceProperty : public PropertyBase
                /* record the change described in our change member */
 
                if (!_changes.added.empty()) {
-                       for (typename ChangeContainer::iterator i = _changes.added.begin(); i != _changes.added.end(); ++i) {
+                       for (typename ChangeContainer::const_iterator i = _changes.added.begin(); i != _changes.added.end(); ++i) {
                                 XMLNode* add_node = new XMLNode ("Add");
                                 child->add_child_nocopy (*add_node);
-                                add_node->add_property ("id", (*i)->id().to_s());
+                               get_content_as_xml (*i, *add_node);
                        }
                }
                if (!_changes.removed.empty()) {
-                       for (typename ChangeContainer::iterator i = _changes.removed.begin(); i != _changes.removed.end(); ++i) {
+                       for (typename ChangeContainer::const_iterator i = _changes.removed.begin(); i != _changes.removed.end(); ++i) {
                                 XMLNode* remove_node = new XMLNode ("Remove");
                                 child->add_child_nocopy (*remove_node);
-                                remove_node->add_property ("id", (*i)->id().to_s());
+                               get_content_as_xml (*i, *remove_node);
                        }
                }
        }
 
+       /** Get a representation of one of our items as XML.  The representation must be sufficient to
+        *  restore the item's state later; an ID is ok if someone else is storing the item state,
+        *  otherwise it needs to be the full state.  The supplied node is an \<Add\> or \<Remove\>
+        *  which this method can either add properties or children to.
+        */
+       virtual void get_content_as_xml (typename ChangeContainer::value_type, XMLNode &) const = 0;
+
        bool set_value (XMLNode const &) {
                /* XXX: not used, but probably should be */
                assert (false);
@@ -163,7 +171,7 @@ class SequenceProperty : public PropertyBase
                           with this diff().
                        */
                         
-                       for (typename ChangeContainer::iterator i = a->changes().added.begin(); i != a->changes().added.end(); ++i) {
+                       for (typename ChangeContainer::const_iterator i = a->changes().added.begin(); i != a->changes().added.end(); ++i) {
                                (*i)->DropReferences.connect_same_thread (*cmd, boost::bind (&Destructible::drop_references, cmd));
                        }
                }
@@ -191,12 +199,12 @@ class SequenceProperty : public PropertyBase
 
                XMLNodeList const & grandchildren = (*i)->children ();
                for (XMLNodeList::const_iterator j = grandchildren.begin(); j != grandchildren.end(); ++j) {
-                       XMLProperty const * prop = (*j)->property ("id");
-                       assert (prop);
-                       PBD::ID id (prop->value ());
-                       typename Container::value_type v = lookup_id (id);
-                       assert (v);
-                       if ((*j)->name() == "Add") {
+
+                       typename Container::value_type v = get_content_from_xml (**j);
+
+                       if (!v) {
+                               warning << "undo transaction references an unknown object" << endmsg;
+                       } else if ((*j)->name() == "Add") {
                                p->_changes.added.insert (v);
                        } else if ((*j)->name() == "Remove") {
                                p->_changes.removed.insert (v);
@@ -206,13 +214,16 @@ class SequenceProperty : public PropertyBase
                return p;
         }
 
+       /** Given an \<Add\> or \<Remove\> node as passed into get_content_to_xml, obtain an item */
+       virtual typename Container::value_type get_content_from_xml (XMLNode const & node) const = 0;
+
        void clear_owned_changes () {
                for (typename Container::iterator i = begin(); i != end(); ++i) {
                        (*i)->clear_changes ();
                }
        }
 
-       void rdiff (std::vector<StatefulDiffCommand*>& cmds) const {
+       void rdiff (std::vector<Command*>& cmds) const {
                for (typename Container::const_iterator i = begin(); i != end(); ++i) {
                        if ((*i)->changed ()) {
                                StatefulDiffCommand* sdc = new StatefulDiffCommand (*i);
@@ -221,7 +232,7 @@ class SequenceProperty : public PropertyBase
                }
        }
 
-        Container rlist() { return _val; }
+        Container rlist() const { return _val; }
 
        /* Wrap salient methods of Sequence
         */
@@ -255,6 +266,11 @@ class SequenceProperty : public PropertyBase
                return _val.erase (f, l);
        }
 
+       void remove (const typename Container::value_type& v) {
+               _changes.remove (v);
+               _val.remove (v);
+       }
+
        void push_back (const typename Container::value_type& v) {
                _changes.add (v);
                _val.push_back (v);
@@ -295,10 +311,10 @@ class SequenceProperty : public PropertyBase
        }
 
        Container& operator= (const Container& other) {
-               for (typename Container::iterator i = _val.begin(); i != _val.end(); ++i) {
+               for (typename Container::const_iterator i = _val.begin(); i != _val.end(); ++i) {
                        _changes.remove (*i);
                }
-               for (typename Container::iterator i = other.begin(); i != other.end(); ++i) {
+               for (typename Container::const_iterator i = other.begin(); i != other.end(); ++i) {
                        _changes.add (*i);
                }
                return _val = other;
@@ -331,6 +347,15 @@ class SequenceProperty : public PropertyBase
         const ChangeRecord& changes () const { return _changes; }
 
 protected:
+
+       /* copy construction only by subclasses */
+       SequenceProperty (SequenceProperty<Container> const & p)
+               : PropertyBase (p)
+               , _val (p._val)
+               , _changes (p._changes)
+               , _update_callback (p._update_callback)
+       {}
+       
        Container _val; ///< our actual container of things
        ChangeRecord _changes; ///< changes to the container (adds/removes) that have happened since clear_changes() was last called
        boost::function<void(const ChangeRecord&)> _update_callback;