(Hopefully) clarify operator= and copy construction behaviour of the Property hierarc...
[ardour.git] / libs / ardour / region.cc
index 8625b17a8a8276b11c14bea9a852f5ecc68ffe1b..43506c78becd10ae1469afa2df52dd6f1c671522 100644 (file)
@@ -23,7 +23,6 @@
 #include <algorithm>
 #include <sstream>
 
-
 #include <glibmm/thread.h>
 #include "pbd/xml++.h"
 #include "pbd/stacktrace.h"
@@ -60,6 +59,7 @@ namespace ARDOUR {
                PBD::PropertyDescriptor<bool> right_of_split;
                PBD::PropertyDescriptor<bool> hidden;
                PBD::PropertyDescriptor<bool> position_locked;
+               PBD::PropertyDescriptor<bool> valid_transients;
                PBD::PropertyDescriptor<framepos_t> start;
                PBD::PropertyDescriptor<framecnt_t> length;
                PBD::PropertyDescriptor<framepos_t> position;
@@ -69,6 +69,7 @@ namespace ARDOUR {
                PBD::PropertyDescriptor<framecnt_t> ancestral_length;
                PBD::PropertyDescriptor<float> stretch;
                PBD::PropertyDescriptor<float> shift;
+               PBD::PropertyDescriptor<PositionLockStyle> position_lock_style;
        }
 }
        
@@ -101,6 +102,8 @@ Region::make_property_quarks ()
         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n",     Properties::hidden.property_id));
        Properties::position_locked.property_id = g_quark_from_static_string (X_("position-locked"));
         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n",    Properties::position_locked.property_id));
+       Properties::valid_transients.property_id = g_quark_from_static_string (X_("valid-transients"));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for valid-transients = %1\n",   Properties::valid_transients.property_id));
        Properties::start.property_id = g_quark_from_static_string (X_("start"));
         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n",      Properties::start.property_id));
        Properties::length.property_id = g_quark_from_static_string (X_("length"));
@@ -119,6 +122,8 @@ Region::make_property_quarks ()
         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch = %1\n",    Properties::stretch.property_id));
        Properties::shift.property_id = g_quark_from_static_string (X_("shift"));
         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n",      Properties::shift.property_id));
+       Properties::position_lock_style.property_id = g_quark_from_static_string (X_("positional-lock-style"));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position_lock_style = %1\n",        Properties::position_lock_style.property_id));
 }
 
 void
@@ -138,6 +143,7 @@ Region::register_properties ()
        add_property (_right_of_split);
        add_property (_hidden);
        add_property (_position_locked);
+       add_property (_valid_transients);
        add_property (_start);
        add_property (_length);
        add_property (_position);
@@ -147,6 +153,7 @@ Region::register_properties ()
        add_property (_ancestral_length);
        add_property (_stretch);
        add_property (_shift);
+       add_property (_position_lock_style);
 }
 
 #define REGION_DEFAULT_STATE(s,l) \
@@ -162,6 +169,7 @@ Region::register_properties ()
        , _right_of_split (Properties::right_of_split, false) \
        , _hidden (Properties::hidden, false) \
        , _position_locked (Properties::position_locked, false) \
+       , _valid_transients (Properties::valid_transients, false) \
        , _start (Properties::start, (s))       \
        , _length (Properties::length, (l))     \
        , _position (Properties::position, 0) \
@@ -170,30 +178,33 @@ Region::register_properties ()
        , _ancestral_start (Properties::ancestral_start, (s)) \
        , _ancestral_length (Properties::ancestral_length, (l)) \
        , _stretch (Properties::stretch, 1.0) \
-       , _shift (Properties::shift, 1.0)
+       , _shift (Properties::shift, 1.0) \
+       , _position_lock_style (Properties::position_lock_style, _type == DataType::AUDIO ? AudioTime : MusicTime)
 
 #define REGION_COPY_STATE(other) \
-         _muted (other->_muted) \
-       , _opaque (other->_opaque) \
-       , _locked (other->_locked) \
-       , _automatic (other->_automatic) \
-       , _whole_file (other->_whole_file) \
-       , _import (other->_import) \
-       , _external (other->_external) \
-       , _sync_marked (other->_sync_marked) \
-       , _left_of_split (other->_left_of_split) \
-       , _right_of_split (other->_right_of_split) \
-       , _hidden (other->_hidden) \
-       , _position_locked (other->_position_locked) \
-       , _start(other->_start) \
-       , _length(other->_length) \
-       , _position(other->_position) \
-       , _sync_position(other->_sync_position) \
-        , _layer (other->_layer) \
-       , _ancestral_start (other->_ancestral_start) \
-       , _ancestral_length (other->_ancestral_length) \
-       , _stretch (other->_stretch) \
-       , _shift (other->_shift)
+         _muted (Properties::muted, other->_muted)                     \
+       , _opaque (Properties::opaque, other->_opaque)          \
+       , _locked (Properties::locked, other->_locked)          \
+       , _automatic (Properties::automatic, other->_automatic) \
+       , _whole_file (Properties::whole_file, other->_whole_file) \
+       , _import (Properties::import, other->_import)          \
+       , _external (Properties::external, other->_external)    \
+       , _sync_marked (Properties::sync_marked, other->_sync_marked) \
+       , _left_of_split (Properties::left_of_split, other->_left_of_split) \
+       , _right_of_split (Properties::right_of_split, other->_right_of_split) \
+       , _hidden (Properties::hidden, other->_hidden)          \
+       , _position_locked (Properties::position_locked, other->_position_locked) \
+       , _valid_transients (Properties::valid_transients, other->_valid_transients) \
+       , _start(Properties::start, other->_start)              \
+       , _length(Properties::length, other->_length)           \
+       , _position(Properties::position, other->_position)     \
+       , _sync_position(Properties::sync_position, other->_sync_position) \
+       , _layer (Properties::layer, other->_layer)             \
+       , _ancestral_start (Properties::ancestral_start, other->_ancestral_start) \
+       , _ancestral_length (Properties::ancestral_length, other->_ancestral_length) \
+       , _stretch (Properties::stretch, other->_stretch)       \
+       , _shift (Properties::shift, other->_shift)             \
+       , _position_lock_style (Properties::position_lock_style, other->_position_lock_style)
 
 /* derived-from-derived constructor (no sources in constructor) */
 Region::Region (Session& s, framepos_t start, framecnt_t length, const string& name, DataType type)
@@ -202,7 +213,6 @@ Region::Region (Session& s, framepos_t start, framecnt_t length, const string& n
        , REGION_DEFAULT_STATE(start,length)
        , _last_length (length)
        , _last_position (0)
-       , _positional_lock_style(AudioTime)
        , _first_edit (EditChangesNothing)
        , _read_data_count(0)
        , _last_layer_op(0)
@@ -220,9 +230,7 @@ Region::Region (const SourceList& srcs)
        , REGION_DEFAULT_STATE(0,0)
        , _last_length (0)
        , _last_position (0)
-        , _positional_lock_style (_type == DataType::AUDIO ? AudioTime : MusicTime)
        , _first_edit (EditChangesNothing)
-       , _valid_transients(false)
        , _read_data_count(0)
        , _last_layer_op (0)
        , _pending_explicit_relayer (false)
@@ -239,10 +247,10 @@ Region::Region (const SourceList& srcs)
 
 /** Create a new Region from part of an existing one, starting at one of two places:
 
-    if @param offset_relative is true, then the start within @param other is given by @param offset
-    (i.e. relative to the start of @param other's sources, the start is @param offset + @param other.start()
+    if \a offset_relative is true, then the start within \a other is given by \a offset
+    (i.e. relative to the start of \a other's sources, the start is \a offset + \a other.start()
 
-    if @param offset_relative is false, then the start within the source is given @param offset.
+    if @param offset_relative is false, then the start within the source is given \a offset.
 */
 Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset, bool offset_relative)
        : SessionObject(other->session(), other->name())
@@ -250,9 +258,7 @@ Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset, boo
        , REGION_COPY_STATE (other)
        , _last_length (other->_last_length)
        , _last_position(other->_last_position) \
-       , _positional_lock_style(other->_positional_lock_style) \
        , _first_edit (EditChangesNothing)
-       , _valid_transients(false)
        , _read_data_count(0)
        , _last_layer_op (0)
        , _pending_explicit_relayer (false)
@@ -276,7 +282,7 @@ Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset, boo
                   property lists. this would be nice to remove.
                */
 
-               _positional_lock_style = other->_positional_lock_style;
+               _position_lock_style = other->_position_lock_style;
                _first_edit = other->_first_edit;
 
                if (offset == 0) {
@@ -357,9 +363,7 @@ Region::Region (boost::shared_ptr<const Region> other, const SourceList& srcs)
        , REGION_COPY_STATE (other)
        , _last_length (other->_last_length)
        , _last_position (other->_last_position)
-        , _positional_lock_style (other->_positional_lock_style)
        , _first_edit (EditChangesID)
-       , _valid_transients (false)
        , _read_data_count (0)
        , _last_layer_op (other->_last_layer_op)
        , _pending_explicit_relayer (false)
@@ -388,9 +392,7 @@ Region::Region (boost::shared_ptr<const Region> other)
        , REGION_COPY_STATE (other)
        , _last_length (other->_last_length)
        , _last_position (other->_last_position)
-        , _positional_lock_style (other->_positional_lock_style)
        , _first_edit (EditChangesID)
-       , _valid_transients(false)
        , _read_data_count(0)
        , _last_layer_op(other->_last_layer_op)
        , _pending_explicit_relayer (false)
@@ -415,6 +417,7 @@ Region::Region (boost::shared_ptr<const Region> other)
 Region::~Region ()
 {
        DEBUG_TRACE (DEBUG::Destruction, string_compose ("Region %1 destructor @ %2\n", _name, this));
+        drop_sources ();
 }
 
 void
@@ -544,18 +547,22 @@ Region::special_set_position (framepos_t pos)
 void
 Region::set_position_lock_style (PositionLockStyle ps)
 {
-       boost::shared_ptr<Playlist> pl (playlist());
+       if (_position_lock_style != ps) {
 
-       if (!pl) {
-               return;
-       }
-
-       _positional_lock_style = ps;
+               boost::shared_ptr<Playlist> pl (playlist());
+               
+               if (!pl) {
+                       return;
+               }
+               
+               _position_lock_style = ps;
+               
+               if (_position_lock_style == MusicTime) {
+                       _session.tempo_map().bbt_time (_position, _bbt_time);
+               }
 
-       if (_positional_lock_style == MusicTime) {
-               _session.tempo_map().bbt_time (_position, _bbt_time);
+               send_change (Properties::position_lock_style);
        }
-
 }
 
 void
@@ -563,7 +570,7 @@ Region::update_position_after_tempo_map_change ()
 {
        boost::shared_ptr<Playlist> pl (playlist());
 
-       if (!pl || _positional_lock_style != MusicTime) {
+       if (!pl || _position_lock_style != MusicTime) {
                return;
        }
 
@@ -604,13 +611,12 @@ Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
                        recompute_position_from_lock_style ();
                }
 
-               invalidate_transients ();
+               //invalidate_transients ();
        }
 
        /* do this even if the position is the same. this helps out
           a GUI that has moved its representation already.
        */
-
        send_change (Properties::position);
 }
 
@@ -642,7 +648,7 @@ Region::set_position_on_top (framepos_t pos, void* /*src*/)
 void
 Region::recompute_position_from_lock_style ()
 {
-       if (_positional_lock_style == MusicTime) {
+       if (_position_lock_style == MusicTime) {
                _session.tempo_map().bbt_time (_position, _bbt_time);
        }
 }
@@ -763,13 +769,31 @@ Region::trim_start (framepos_t new_position, void */*src*/)
 
 void
 Region::trim_front (framepos_t new_position, void *src)
+{
+       modify_front (new_position, false, src);
+}
+
+void
+Region::cut_front (nframes_t new_position, void *src)
+{
+       modify_front (new_position, true, src);
+}
+
+void
+Region::cut_end (nframes_t new_endpoint, void *src)
+{
+       modify_end (new_endpoint, true, src);
+}
+
+void
+Region::modify_front (nframes_t new_position, bool reset_fade, void *src)
 {
        if (locked()) {
                return;
        }
 
-       framepos_t end = last_frame();
-       framepos_t source_zero;
+       nframes_t end = last_frame();
+       nframes_t source_zero;
 
        if (_position > _start) {
                source_zero = _position - _start;
@@ -778,46 +802,66 @@ Region::trim_front (framepos_t new_position, void *src)
        }
 
        if (new_position < end) { /* can't trim it zero or negative length */
-
-               framecnt_t newlen;
+               
+               nframes_t newlen = 0;
+               nframes64_t delta = 0;
 
                /* can't trim it back passed where source position zero is located */
-
+               
                new_position = max (new_position, source_zero);
-
-
+               
                if (new_position > _position) {
                        newlen = _length - (new_position - _position);
+                       delta = -1 * (new_position - _position);
                } else {
                        newlen = _length + (_position - new_position);
+                       delta = _position - new_position;
                }
-
+               
                trim_to_internal (new_position, newlen, src);
-               if (!property_changes_suspended()) {
+               
+               if (reset_fade) {
+                        _right_of_split = true;
+               }
+       
+                if (!property_changes_suspended()) {
                        recompute_at_start ();
                }
+               
+               if (_transients.size() > 0){
+                       adjust_transients(delta);
+               }
        }
 }
 
-/** @param new_endpoint New region end point, such that, for example,
- *  a region at 0 of length 10 has an endpoint of 9.
- */
-
 void
-Region::trim_end (framepos_t new_endpoint, void */*src*/)
+Region::modify_end (nframes_t new_endpoint, bool reset_fade, void *src)
 {
        if (locked()) {
                return;
        }
 
        if (new_endpoint > _position) {
-               trim_to_internal (_position, new_endpoint - _position + 1, this);
+               trim_to_internal (_position, new_endpoint - _position +1, this);
+               if (reset_fade) {
+                        _left_of_split = true;
+               }
                if (!property_changes_suspended()) {
                        recompute_at_end ();
                }
        }
 }
 
+/** @param new_endpoint New region end point, such that, for example,
+ *  a region at 0 of length 10 has an endpoint of 9.
+ */
+
+void
+Region::trim_end (framepos_t new_endpoint, void* src)
+{
+       modify_end (new_endpoint, false, src);
+}
+
 void
 Region::trim_to (framepos_t position, framecnt_t length, void *src)
 {
@@ -857,7 +901,6 @@ Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/)
                        new_start = _start + start_shift;
                }
 
-
        } else if (start_shift < 0) {
 
                if (_start < -start_shift) {
@@ -865,6 +908,7 @@ Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/)
                } else {
                        new_start = _start + start_shift;
                }
+
        } else {
                new_start = _start;
        }
@@ -969,9 +1013,13 @@ Region::set_position_locked (bool yn)
        }
 }
 
+/** Set the region's sync point.
+ *  @param absolute_pos Session time.
+ */
 void
 Region::set_sync_position (framepos_t absolute_pos)
 {
+       /* position within our file */
        framepos_t const file_pos = _start + (absolute_pos - _position);
 
        if (file_pos != _sync_position) {
@@ -996,11 +1044,10 @@ Region::clear_sync_position ()
        }
 }
 
+/* @return the sync point relative the first frame of the region */
 framepos_t
 Region::sync_offset (int& dir) const
 {
-       /* returns the sync point relative the first frame of the region */
-
        if (sync_marked()) {
                if (_sync_position > _start) {
                        dir = 1;
@@ -1038,13 +1085,15 @@ Region::adjust_to_sync (framepos_t pos) const
        return pos;
 }
 
+/** @return Sync position in session time */
 framepos_t
 Region::sync_position() const
 {
        if (sync_marked()) {
-               return _sync_position;
+               return _position - _start + _sync_position;
        } else {
-               return _start;
+               /* if sync has not been marked, use the start of the region */
+               return _position;
        }
 }
 
@@ -1096,10 +1145,12 @@ Region::set_layer (layer_t l)
 }
 
 XMLNode&
-Region::state (bool /*full_state*/)
+Region::state ()
 {
        XMLNode *node = new XMLNode ("Region");
        char buf[64];
+       char buf2[64];
+       LocaleGuard lg (X_("POSIX"));
        const char* fe = NULL;
 
        add_properties (*node);
@@ -1127,20 +1178,35 @@ Region::state (bool /*full_state*/)
 
        /* note: flags are stored by derived classes */
 
-       if (_positional_lock_style != AudioTime) {
-               node->add_property ("positional-lock-style", enum_2_string (_positional_lock_style));
+       if (_position_lock_style != AudioTime) {
                stringstream str;
                str << _bbt_time;
                node->add_property ("bbt-position", str.str());
        }
 
+       for (uint32_t n=0; n < _sources.size(); ++n) {
+               snprintf (buf2, sizeof(buf2), "source-%d", n);
+               _sources[n]->id().print (buf, sizeof(buf));
+               node->add_property (buf2, buf);
+       }
+
+       for (uint32_t n=0; n < _master_sources.size(); ++n) {
+               snprintf (buf2, sizeof(buf2), "master-source-%d", n);
+               _master_sources[n]->id().print (buf, sizeof (buf));
+               node->add_property (buf2, buf);
+       }
+
+       if (_extra_xml) {
+               node->add_child_copy (*_extra_xml);
+       }
+
        return *node;
 }
 
 XMLNode&
 Region::get_state ()
 {
-       return state (true);
+       return state ();
 }
 
 int
@@ -1155,29 +1221,24 @@ Region::_set_state (const XMLNode& node, int version, PropertyChange& what_chang
 {
        const XMLProperty* prop;
 
-       what_changed = set_properties (node);
+       what_changed = set_values (node);
 
        if ((prop = node.property (X_("id")))) {
                _id = prop->value();
        }
 
-       if ((prop = node.property ("positional-lock-style")) != 0) {
-               _positional_lock_style = PositionLockStyle (string_2_enum (prop->value(), _positional_lock_style));
-
-               if (_positional_lock_style == MusicTime) {
-                       if ((prop = node.property ("bbt-position")) == 0) {
-                               /* missing BBT info, revert to audio time locking */
-                               _positional_lock_style = AudioTime;
-                       } else {
-                               if (sscanf (prop->value().c_str(), "%d|%d|%d",
-                                           &_bbt_time.bars,
-                                           &_bbt_time.beats,
-                                           &_bbt_time.ticks) != 3) {
-                                       _positional_lock_style = AudioTime;
-                               }
+       if (_position_lock_style == MusicTime) {
+               if ((prop = node.property ("bbt-position")) == 0) {
+                       /* missing BBT info, revert to audio time locking */
+                       _position_lock_style = AudioTime;
+               } else {
+                       if (sscanf (prop->value().c_str(), "%d|%d|%d",
+                                   &_bbt_time.bars,
+                                   &_bbt_time.beats,
+                                   &_bbt_time.ticks) != 3) {
+                               _position_lock_style = AudioTime;
                        }
                }
-
        }
 
        /* fix problems with old sessions corrupted by impossible
@@ -1207,11 +1268,6 @@ Region::_set_state (const XMLNode& node, int version, PropertyChange& what_chang
        }
 
        if (send) {
-               cerr << _name << ": final change to be sent: ";
-               for (PropertyChange::iterator i = what_changed.begin(); i != what_changed.end(); ++i) {
-                       cerr << g_quark_to_string ((GQuark) *i) << ' ';
-               }
-               cerr << endl;
                send_change (what_changed);
        }
        
@@ -1305,7 +1361,7 @@ Region::region_list_equivalent (boost::shared_ptr<const Region> other) const
 void
 Region::source_deleted (boost::weak_ptr<Source>)
 {
-       _sources.clear ();
+        drop_sources ();
 
        if (!_session.deletion_in_progress()) {
                /* this is a very special case: at least one of the region's
@@ -1336,8 +1392,16 @@ Region::master_source_names ()
 void
 Region::set_master_sources (const SourceList& srcs)
 {
+        for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
+                (*i)->dec_use_count ();
+        }
+
        _master_sources = srcs;
        assert (_sources.size() == _master_sources.size());
+
+        for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
+                (*i)->inc_use_count ();
+        }
 }
 
 bool
@@ -1345,6 +1409,11 @@ Region::source_equivalent (boost::shared_ptr<const Region> other) const
 {
        if (!other)
                return false;
+        
+        if ((_sources.size() != other->_sources.size()) ||
+            (_master_sources.size() != other->_master_sources.size())) {
+                return false;
+        }
 
        SourceList::const_iterator i;
        SourceList::const_iterator io;
@@ -1378,6 +1447,7 @@ Region::uses_source (boost::shared_ptr<const Source> source) const
 sframes_t
 Region::source_length(uint32_t n) const
 {
+        assert (n < _sources.size());
        return _sources[n]->length(_position - _start);
 }
 
@@ -1390,7 +1460,7 @@ Region::verify_length (framecnt_t len)
 
        framecnt_t maxlen = 0;
 
-       for (uint32_t n=0; n < _sources.size(); ++n) {
+       for (uint32_t n = 0; n < _sources.size(); ++n) {
                maxlen = max (maxlen, source_length(n) - _start);
        }
 
@@ -1408,7 +1478,7 @@ Region::verify_start_and_length (framepos_t new_start, framecnt_t& new_length)
 
        framecnt_t maxlen = 0;
 
-       for (uint32_t n=0; n < _sources.size(); ++n) {
+       for (uint32_t n = 0; n < _sources.size(); ++n) {
                maxlen = max (maxlen, source_length(n) - new_start);
        }
 
@@ -1424,7 +1494,7 @@ Region::verify_start (framepos_t pos)
                return true;
        }
 
-       for (uint32_t n=0; n < _sources.size(); ++n) {
+       for (uint32_t n = 0; n < _sources.size(); ++n) {
                if (pos > source_length(n) - _length) {
                        return false;
                }
@@ -1439,7 +1509,7 @@ Region::verify_start_mutable (framepos_t& new_start)
                return true;
        }
 
-       for (uint32_t n=0; n < _sources.size(); ++n) {
+       for (uint32_t n = 0; n < _sources.size(); ++n) {
                if (new_start > source_length(n) - _length) {
                        new_start = source_length(n) - _length;
                }
@@ -1476,8 +1546,25 @@ Region::invalidate_transients ()
 {
        _valid_transients = false;
        _transients.clear ();
+       
+       send_change (PropertyChange (Properties::valid_transients));
 }
 
+void
+Region::drop_sources ()
+{
+        for (SourceList::const_iterator i = _sources.begin (); i != _sources.end(); ++i) {
+                (*i)->dec_use_count ();
+        }
+
+       _sources.clear ();
+
+        for (SourceList::const_iterator i = _master_sources.begin (); i != _master_sources.end(); ++i) {
+                (*i)->dec_use_count ();
+        }
+
+        _master_sources.clear ();
+}
 
 void
 Region::use_sources (SourceList const & s)
@@ -1485,31 +1572,18 @@ Region::use_sources (SourceList const & s)
        set<boost::shared_ptr<Source> > unique_srcs;
 
        for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
-               _sources.push_back (*i);
-               (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
-               unique_srcs.insert (*i);
-       }
 
-       for (SourceList::const_iterator i = s.begin (); i != s.end(); ++i) {
+               _sources.push_back (*i);
+                (*i)->inc_use_count ();
                _master_sources.push_back (*i);
-               if (unique_srcs.find (*i) == unique_srcs.end()) {
-                       (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
-               }
-       }
-}
-
-PropertyList*
-Region::property_factory (const XMLNode& history_node) const
-{
-        PropertyList* prop_list = new PropertyList;
+                (*i)->inc_use_count ();
 
-        for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
-                PropertyBase* prop = i->second->maybe_clone_self_if_found_in_history_node (history_node);
+                /* connect only once to DropReferences, even if sources are replicated
+                 */
 
-                if (prop) {
-                        prop_list->add (prop);
+               if (unique_srcs.find (*i) == unique_srcs.end ()) {
+                       unique_srcs.insert (*i);
+                        (*i)->DropReferences.connect_same_thread (*this, boost::bind (&Region::source_deleted, this, boost::weak_ptr<Source>(*i)));
                 }
-        }
-
-        return prop_list;
+       }
 }