#include <string>
#include <climits>
+#include <boost/lexical_cast.hpp>
+
#include "pbd/failed_constructor.h"
-#include "pbd/stl_delete.h"
+#include "pbd/stateful_diff_command.h"
#include "pbd/xml++.h"
-#include "pbd/stacktrace.h"
#include "ardour/debug.h"
#include "ardour/playlist.h"
{
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;
}
}
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);
-
- cerr << "pdiff on " << _playlist.name() << " before contains "
- << b->change().added.size() << " adds and " << b->change().removed.size() << " removes\n";
- cerr << "pdiff on " << _playlist.name() << " after contains "
- << a->change().added.size() << " adds and " << a->change().removed.size() << " removes\n";
-
+ undo.add (b);
+ redo.add (a);
}
}
init (hide);
first_set_state = false;
_name = nom;
+ _set_sort_id ();
}
init (hide);
_name = "unnamed"; /* reset by set_state */
+ _set_sort_id ();
/* set state called by derived class */
}
break;
}
- _session.region_name (new_name, region->name(), false);
+ RegionFactory::region_name (new_name, region->name(), false);
PropertyList plist;
- plist.add (Properties::start, offset);
+ plist.add (Properties::start, region->start() + offset);
plist.add (Properties::length, len);
plist.add (Properties::name, new_name);
plist.add (Properties::layer, region->layer());
_shuffling = false;
_nudging = false;
in_set_state = 0;
+ in_update = false;
_edit_mode = Config->get_edit_mode();
in_flush = false;
in_partition = false;
/* 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)
{
if (_refcnt > 2) {
return false;
- } else {
- return SessionObject::set_name(str);
- }
+ }
+
+ bool ret = SessionObject::set_name(str);
+ if (ret) {
+ _set_sort_id ();
+ }
+ return ret;
}
/***********************************************************************
void
Playlist::begin_undo ()
{
+ in_update = true;
freeze ();
}
Playlist::end_undo ()
{
thaw ();
+ in_update = false;
}
void
if (g_atomic_int_dec_and_test (&block_notifications)) {
flush_notifications ();
}
+
}
void
/* the length change might not be true, but we have to act
as though it could be.
*/
-
+
if (holding_state()) {
pending_adds.insert (r);
pending_contents_change = true;
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;
- plist.add (Properties::start, 0);
+ plist.add (Properties::start, region->start());
plist.add (Properties::length, length);
plist.add (Properties::name, name);
plist.add (Properties::layer, region->layer());
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 ();
}
possibly_splice_unlocked (pos, -distance);
if (!holding_state ()) {
- relayer ();
+ relayer ();
remove_dependents (region);
if (old_length != _get_maximum_extent()) {
if (!cutting) {
/* "middle" ++++++ */
- _session.region_name (new_name, current->name(), false);
+ RegionFactory::region_name (new_name, current->name(), false);
PropertyList plist;
- plist.add (Properties::start, pos2 - pos1);
+ plist.add (Properties::start, current->start() + (pos2 - pos1));
plist.add (Properties::length, pos3 - pos2);
plist.add (Properties::name, new_name);
plist.add (Properties::layer, regions.size());
/* "end" ====== */
- _session.region_name (new_name, current->name(), false);
+ RegionFactory::region_name (new_name, current->name(), false);
PropertyList plist;
- plist.add (Properties::start, pos3 - pos1);
+ plist.add (Properties::start, current->start() + (pos3 - pos1));
plist.add (Properties::length, pos4 - pos3);
plist.add (Properties::name, new_name);
plist.add (Properties::layer, regions.size());
current->suspend_property_changes ();
thawlist.push_back (current);
- current->trim_end (pos2, this);
+ current->cut_end (pos2 - 1, this);
} else if (overlap == OverlapEnd) {
/* end +++++ */
- _session.region_name (new_name, current->name(), false);
+ RegionFactory::region_name (new_name, current->name(), false);
PropertyList plist;
- plist.add (Properties::start, pos2 - pos1);
+ plist.add (Properties::start, current->start() + (pos2 - pos1));
plist.add (Properties::length, pos4 - pos2);
plist.add (Properties::name, new_name);
plist.add (Properties::layer, regions.size());
current->suspend_property_changes ();
thawlist.push_back (current);
- current->trim_end (pos2, this);
+ current->cut_end (pos2 - 1, this);
} else if (overlap == OverlapStart) {
if (!cutting) {
/* front **** */
- _session.region_name (new_name, current->name(), false);
+ RegionFactory::region_name (new_name, current->name(), false);
PropertyList plist;
- plist.add (Properties::start, 0);
+ plist.add (Properties::start, current->start());
plist.add (Properties::length, pos3 - pos1);
plist.add (Properties::name, new_name);
plist.add (Properties::layer, regions.size());
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;
- plist.add (Properties::start, 0);
+ plist.add (Properties::start, region->start());
plist.add (Properties::length, length);
plist.add (Properties::name, name);
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;
left = RegionFactory::create (region, plist);
}
- _session.region_name (after_name, region->name(), false);
+ RegionFactory::region_name (after_name, region->name(), false);
{
PropertyList plist;
}
regions.clear ();
+
+ for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
+ remove_dependents (*s);
+ }
}
if (with_signals) {
+
+ for (set<boost::shared_ptr<Region> >::iterator s = pending_removes.begin(); s != pending_removes.end(); ++s) {
+ RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
+ }
+
+ pending_removes.clear ();
pending_length = false;
LengthChanged ();
pending_contents_change = false;
return false;
}
+void
+Playlist::rdiff (vector<StatefulDiffCommand*>& cmds) const
+{
+ RegionLock rlock (const_cast<Playlist *> (this));
+
+ for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
+ if ((*i)->changed ()) {
+ StatefulDiffCommand* sdc = new StatefulDiffCommand (*i);
+ cmds.push_back (sdc);
+ }
+ }
+}
+
+void
+Playlist::clear_owned_history ()
+{
+ RegionLock rlock (this);
+
+ for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+ (*i)->clear_history ();
+ }
+}
+
void
Playlist::update (const RegionListProperty::ChangeRecord& change)
{
for (RegionListProperty::ChangeContainer::iterator i = change.removed.begin(); i != change.removed.end(); ++i) {
remove_region (*i);
}
+
thaw ();
}
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));
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")) {
}
}
- clear (false);
+ clear (true);
nlist = node.children();
error << _("Playlist: cannot create region from XML") << endmsg;
continue;
}
-
+
add_region (region, region->position(), 1.0);
// So that layer_op ordering doesn't get screwed up
check_dependents (*r, false);
}
- clear_pending (); // this makes thaw() do nothing
thaw ();
notify_contents_changed ();
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
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
void
Playlist::timestamp_layer_op (boost::shared_ptr<Region> region)
{
-// struct timeval tv;
-// gettimeofday (&tv, 0);
region->set_last_layer_op (++layer_op_counter);
}