commits 6001-6525 inclusive from 2.X applied to 3.0
[ardour.git] / libs / ardour / playlist.cc
index 2b9ce7824f2d309f5fcf8cd2b43ccc3bc158ab3f..6fc7fdc2cffa9d92020485a07aa77d672b850647 100644 (file)
 #include <string>
 #include <climits>
 
+#include <boost/lexical_cast.hpp>
+
 #include "pbd/failed_constructor.h"
 #include "pbd/stateful_diff_command.h"
-#include "pbd/stl_delete.h"
 #include "pbd/xml++.h"
 
 #include "ardour/debug.h"
@@ -113,13 +114,10 @@ RegionListProperty::lookup_id (const ID& id)
 {
         boost::shared_ptr<Region> ret =  _playlist.region_by_id (id);
         
-        if (!ret) {
-                ret = _playlist.session().region_by_id (id);
-        }
-
         if (!ret) {
                 ret = RegionFactory::region_by_id (id);
         }
+
         return ret;
 }
 
@@ -133,16 +131,18 @@ RegionListProperty::copy_for_history () const
 }
 
 void 
-RegionListProperty::diff (PropertyList& before, PropertyList& after) const
+RegionListProperty::diff (PropertyList& undo, PropertyList& redo) const
 {
-        if (_have_old) {
+        if (changed()) {
+               /* list of the removed/added regions since clear_history() was last called */
                 RegionListProperty* a = copy_for_history ();
-                RegionListProperty* b = copy_for_history ();
 
+               /* the same list, but with removed/added lists swapped (for undo purposes) */
+                RegionListProperty* b = copy_for_history ();
                 b->invert_changes ();
 
-                before.add (b);
-                after.add (a);
+                undo.add (b);
+                redo.add (a);
         }
 }
 
@@ -154,6 +154,7 @@ Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
        init (hide);
        first_set_state = false;
        _name = nom;
+        _set_sort_id ();
 
 }
 
@@ -168,6 +169,7 @@ Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide
 
        init (hide);
        _name = "unnamed"; /* reset by set_state */
+        _set_sort_id ();
 
        /* set state called by derived class */
 }
@@ -264,7 +266,7 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, f
                        break;
                }
 
-               _session.region_name (new_name, region->name(), false);
+               RegionFactory::region_name (new_name, region->name(), false);
 
                PropertyList plist; 
 
@@ -331,6 +333,7 @@ Playlist::init (bool hide)
        _shuffling = false;
        _nudging = false;
        in_set_state = 0;
+        in_update = false;
        _edit_mode = Config->get_edit_mode();
        in_flush = false;
        in_partition = false;
@@ -362,6 +365,32 @@ Playlist::~Playlist ()
        /* GoingAway must be emitted by derived classes */
 }
 
+void
+Playlist::_set_sort_id ()
+{
+        /*
+          Playlists are given names like <track name>.<id>
+          or <track name>.<edit group name>.<id> where id
+          is an integer. We extract the id and sort by that.
+        */
+        
+        size_t dot_position = _name.val().find_last_of(".");
+
+        if (dot_position == string::npos) {
+                _sort_id = 0;
+        } else {
+                string t = _name.val().substr(dot_position + 1);
+
+                try {
+                        _sort_id = boost::lexical_cast<int>(t);
+                }
+
+                catch (boost::bad_lexical_cast e) {
+                        _sort_id = 0;
+                }
+        }
+}
+
 bool
 Playlist::set_name (const string& str)
 {
@@ -373,9 +402,13 @@ Playlist::set_name (const string& str)
 
        if (_refcnt > 2) {
                return false;
-       } else {
-               return SessionObject::set_name(str);
-       }
+       } 
+
+        bool ret =  SessionObject::set_name(str);
+        if (ret) {
+                _set_sort_id ();
+        }
+        return ret;
 }
 
 /***********************************************************************
@@ -389,6 +422,7 @@ Playlist::set_name (const string& str)
 void
 Playlist::begin_undo ()
 {
+        in_update = true;
        freeze ();
 }
 
@@ -396,6 +430,7 @@ void
 Playlist::end_undo ()
 {
        thaw ();
+        in_update = false;
 }
 
 void
@@ -660,7 +695,7 @@ Playlist::add_region (boost::shared_ptr<Region> region, framepos_t position, flo
        if (floor (times) != times) {
                length = (framecnt_t) floor (region->length() * (times - floor (times)));
                string name;
-               _session.region_name (name, region->name(), false);
+               RegionFactory::region_name (name, region->name(), false);
 
                {
                        PropertyList plist;
@@ -719,8 +754,8 @@ Playlist::add_region_internal (boost::shared_ptr<Region> region, framepos_t posi
 
        possibly_splice_unlocked (position, region->length(), region);
 
-       if (!holding_state () && !in_set_state) {
-               /* layers get assigned from XML state */
+       if (!holding_state ()) {
+               /* layers get assigned from XML state, and are not reset during undo/redo */
                relayer ();
        }
 
@@ -794,7 +829,7 @@ Playlist::remove_region_internal (boost::shared_ptr<Region> region)
                        possibly_splice_unlocked (pos, -distance);
 
                        if (!holding_state ()) {
-                               relayer ();
+                                relayer ();
                                remove_dependents (region);
 
                                if (old_length != _get_maximum_extent()) {
@@ -930,7 +965,7 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re
                                if (!cutting) {
                                        /* "middle" ++++++ */
 
-                                       _session.region_name (new_name, current->name(), false);
+                                       RegionFactory::region_name (new_name, current->name(), false);
 
                                        PropertyList plist;
                                        
@@ -949,7 +984,7 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re
 
                                /* "end" ====== */
 
-                               _session.region_name (new_name, current->name(), false);
+                               RegionFactory::region_name (new_name, current->name(), false);
 
                                PropertyList plist;
                                
@@ -969,7 +1004,7 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re
 
                                current->suspend_property_changes ();
                                thawlist.push_back (current);
-                               current->trim_end (pos2, this);
+                               current->cut_end (pos2 - 1, this);
 
                        } else if (overlap == OverlapEnd) {
 
@@ -987,7 +1022,7 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re
 
                                        /* end +++++ */
 
-                                       _session.region_name (new_name, current->name(), false);
+                                       RegionFactory::region_name (new_name, current->name(), false);
                                        
                                        PropertyList plist;
                                        
@@ -1008,7 +1043,7 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re
 
                                current->suspend_property_changes ();
                                thawlist.push_back (current);
-                               current->trim_end (pos2, this);
+                               current->cut_end (pos2 - 1, this);
 
                        } else if (overlap == OverlapStart) {
 
@@ -1030,7 +1065,7 @@ Playlist::partition_internal (framepos_t start, framepos_t end, bool cutting, Re
 
                                if (!cutting) {
                                        /* front **** */
-                                       _session.region_name (new_name, current->name(), false);
+                                       RegionFactory::region_name (new_name, current->name(), false);
 
                                        PropertyList plist;
                                        
@@ -1234,7 +1269,7 @@ Playlist::duplicate (boost::shared_ptr<Region> region, framepos_t position, floa
        if (floor (times) != times) {
                framecnt_t length = (framecnt_t) floor (region->length() * (times - floor (times)));
                string name;
-               _session.region_name (name, region->name(), false);
+               RegionFactory::region_name (name, region->name(), false);
                
                {
                        PropertyList plist;
@@ -1335,7 +1370,7 @@ Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_p
        before = playlist_position - region->position();
        after = region->length() - before;
 
-       _session.region_name (before_name, region->name(), false);
+       RegionFactory::region_name (before_name, region->name(), false);
 
        {
                PropertyList plist;
@@ -1348,7 +1383,7 @@ Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_p
                left = RegionFactory::create (region, plist);
        }
 
-       _session.region_name (after_name, region->name(), false);
+       RegionFactory::region_name (after_name, region->name(), false);
 
        {
                PropertyList plist;
@@ -2063,6 +2098,7 @@ Playlist::update (const RegionListProperty::ChangeRecord& change)
         for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
                 remove_region (*i);
         }
+
         thaw ();
 }
 
@@ -2074,8 +2110,6 @@ Playlist::property_factory (const XMLNode& history_node) const
 
         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
 
-                /* XXX property name needs capitalizing */
-
                 if ((*i)->name() == capitalize (regions.property_name())) {
                         
                         RegionListProperty* rlp = new RegionListProperty (*const_cast<Playlist*> (this));
@@ -2123,6 +2157,7 @@ Playlist::set_state (const XMLNode& node, int version)
 
                if (prop->name() == X_("name")) {
                        _name = prop->value();
+                        _set_sort_id ();
                } else if (prop->name() == X_("id")) {
                         _id = prop->value();
                } else if (prop->name() == X_("orig_diskstream_id")) {
@@ -2306,6 +2341,12 @@ Playlist::set_edit_mode (EditMode mode)
 void
 Playlist::relayer ()
 {
+        /* never compute layers when changing state for undo/redo or setting from XML */
+
+        if (in_update || in_set_state) {
+                return;
+        }
+
        bool changed = false;
 
        /* Build up a new list of regions on each layer, stored in a set of lists
@@ -2449,22 +2490,48 @@ void
 Playlist::raise_region_to_top (boost::shared_ptr<Region> region)
 {
        /* does nothing useful if layering mode is later=higher */
-       if ((_session.config.get_layer_model() == MoveAddHigher) ||
-           (_session.config.get_layer_model() == AddHigher)) {
-               timestamp_layer_op (region);
-               relayer ();
+       switch (_session.config.get_layer_model()) {
+       case LaterHigher:
+               return;
+       default:
+               break;
+       }
+
+       layer_t top = regions.size() - 1;
+
+       if (region->layer() >= top) {
+               /* already on the top */
+               return;
        }
+
+       move_region_to_layer (top, region, 1);
+       /* mark the region's last_layer_op as now, so that it remains on top when
+          doing future relayers (until something else takes over)
+        */
+       timestamp_layer_op (region);
 }
 
 void
 Playlist::lower_region_to_bottom (boost::shared_ptr<Region> region)
 {
        /* does nothing useful if layering mode is later=higher */
-       if ((_session.config.get_layer_model() == MoveAddHigher) ||
-           (_session.config.get_layer_model() == AddHigher)) {
-               region->set_last_layer_op (0);
-               relayer ();
+       switch (_session.config.get_layer_model()) {
+       case LaterHigher:
+               return;
+       default:
+               break;
        }
+
+       if (region->layer() == 0) {
+               /* already on the bottom */
+               return;
+       }
+
+       move_region_to_layer (0, region, -1);
+       /* force region's last layer op to zero so that it stays at the bottom
+          when doing future relayers
+       */
+       region->set_last_layer_op (0);
 }
 
 int
@@ -2647,8 +2714,6 @@ Playlist::set_frozen (bool yn)
 void
 Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
 {
-//     struct timeval tv;
-//     gettimeofday (&tv, 0);
        region->set_last_layer_op (++layer_op_counter);
 }