Add Lua bindings for RegionMap and region list
[ardour.git] / libs / pbd / pbd / sequence_property.h
index 7d94a4be6b941573de6dffeaa08b156f013b9679..4069340e429bb6f6ac7432d825600c1ae83771f4 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 {
 
@@ -42,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;
@@ -89,18 +91,18 @@ class SequenceProperty : public PropertyBase
 
                 XMLNode* child = new XMLNode (PBD::capitalize (property_name()));
                 history_node->add_child_nocopy (*child);
-                
+
                /* 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);
                                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);
                                get_content_as_xml (*i, *remove_node);
@@ -110,7 +112,7 @@ class SequenceProperty : public PropertyBase
 
        /** 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>
+        *  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;
@@ -124,13 +126,13 @@ class SequenceProperty : public PropertyBase
        void get_value (XMLNode & node) const {
                 for (typename Container::const_iterator i = _val.begin(); i != _val.end(); ++i) {
                         node.add_child_nocopy ((*i)->get_state ());
-                } 
+                }
        }
 
        bool changed () const {
                return !_changes.added.empty() || !_changes.removed.empty();
        }
-       
+
        void clear_changes () {
                _changes.added.clear ();
                _changes.removed.clear ();
@@ -142,7 +144,7 @@ class SequenceProperty : public PropertyBase
        }
 
        /** Given a record of changes to this property, pass it to a callback that will
-        *  update the property in some appropriate way. 
+        *  update the property in some appropriate way.
         *
         *  This exists because simply using std::sequence methods to add/remove items
         *  from the property is far too simplistic - the semantics of add/remove may
@@ -156,20 +158,20 @@ class SequenceProperty : public PropertyBase
                if (!changed ()) {
                        return;
                }
-               
+
                /* Create a property with just the changes and not the actual values */
                SequenceProperty<Container>* a = create ();
                a->_changes = _changes;
                changes.add (a);
-               
+
                if (cmd) {
                        /* whenever one of the items emits DropReferences, make sure
                           that the Destructible we've been told to notify hears about
                           it. the Destructible is likely to be the Command being built
                           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));
                        }
                }
@@ -180,7 +182,7 @@ class SequenceProperty : public PropertyBase
                XMLNodeList const children = node.children ();
 
                /* find the node for this property name */
-               
+
                std::string const c = capitalize (property_name ());
                XMLNodeList::const_iterator i = children.begin();
                while (i != children.end() && (*i)->name() != c) {
@@ -192,16 +194,17 @@ class SequenceProperty : public PropertyBase
                }
 
                /* create a property with the changes */
-               
+
                SequenceProperty<Container>* p = create ();
 
                XMLNodeList const & grandchildren = (*i)->children ();
                for (XMLNodeList::const_iterator j = grandchildren.begin(); j != grandchildren.end(); ++j) {
 
                        typename Container::value_type v = get_content_from_xml (**j);
-                       assert (v);
-                       
-                       if ((*j)->name() == "Add") {
+
+                       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);
@@ -211,7 +214,7 @@ class SequenceProperty : public PropertyBase
                return p;
         }
 
-       /** Given an <Add> or <Remove> node as passed into get_content_to_xml, obtain an item */
+       /** 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 () {
@@ -229,7 +232,7 @@ class SequenceProperty : public PropertyBase
                }
        }
 
-        Container rlist() { return _val; }
+        Container rlist() const { return _val; }
 
        /* Wrap salient methods of Sequence
         */
@@ -298,49 +301,49 @@ class SequenceProperty : public PropertyBase
                }
                _val.clear ();
        }
-       
-       typename Container::size_type size() const { 
+
+       typename Container::size_type size() const {
                return _val.size();
        }
 
-       bool empty() const { 
+       bool empty() const {
                return _val.empty();
        }
 
        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;
        }
 
-       typename Container::reference front() { 
+       typename Container::reference front() {
                return _val.front ();
        }
 
-       typename Container::const_reference front() const { 
+       typename Container::const_reference front() const {
                return _val.front ();
        }
 
-       typename Container::reference back() { 
+       typename Container::reference back() {
                return _val.back ();
        }
 
-       typename Container::const_reference back() const { 
+       typename Container::const_reference back() const {
                return _val.back ();
        }
 
-       void sort() { 
+       void sort() {
                _val.sort ();
        }
 
        template<class BinaryPredicate> void sort(BinaryPredicate comp) {
                _val.sort (comp);
        }
-        
+
         const ChangeRecord& changes () const { return _changes; }
 
 protected:
@@ -352,12 +355,12 @@ protected:
                , _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;
 
-private:       
+private:
        virtual SequenceProperty<Container>* create () const = 0;
 };