summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2010-08-26 01:44:11 +0000
committerCarl Hetherington <carl@carlh.net>2010-08-26 01:44:11 +0000
commitc243a02c998f585295f2179657673e2cf0fa4428 (patch)
tree1a18ca901b5f7fb1270938e2fb62f7e2636400ef
parentdf2fd9491904aba95e08e1e26552be609530ee83 (diff)
Fix crossfade undo using the stateful diff system. Fixes #3257.
git-svn-id: svn://localhost/ardour2/branches/3.0@7694 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/crossfade_edit.cc4
-rw-r--r--gtk2_ardour/editor_drag.cc16
-rw-r--r--gtk2_ardour/editor_ops.cc29
-rw-r--r--gtk2_ardour/route_time_axis.cc18
-rw-r--r--libs/ardour/ardour/audioplaylist.h35
-rw-r--r--libs/ardour/ardour/crossfade.h2
-rw-r--r--libs/ardour/ardour/playlist.h6
-rw-r--r--libs/ardour/ardour/session.h2
-rw-r--r--libs/ardour/audio_playlist.cc75
-rw-r--r--libs/ardour/crossfade.cc4
-rw-r--r--libs/ardour/globals.cc3
-rw-r--r--libs/ardour/playlist.cc44
-rw-r--r--libs/ardour/session_state.cc8
-rw-r--r--libs/ardour/wscript2
-rw-r--r--libs/pbd/pbd/command.h4
-rw-r--r--libs/pbd/pbd/property_basics.h2
-rw-r--r--libs/pbd/pbd/sequence_property.h31
-rw-r--r--libs/pbd/pbd/stateful.h2
-rw-r--r--libs/pbd/pbd/stateful_diff_command.h2
-rw-r--r--libs/pbd/stateful.cc2
-rw-r--r--libs/pbd/stateful_diff_command.cc6
21 files changed, 225 insertions, 72 deletions
diff --git a/gtk2_ardour/crossfade_edit.cc b/gtk2_ardour/crossfade_edit.cc
index b6dcf07920..49e5ee0609 100644
--- a/gtk2_ardour/crossfade_edit.cc
+++ b/gtk2_ardour/crossfade_edit.cc
@@ -788,10 +788,10 @@ CrossfadeEditor::apply ()
_session->begin_reversible_command (_("Edit crossfade"));
XMLNode& before = xfade->get_state ();
-
+
_apply_to (xfade);
- _session->add_command (new MementoCommand<Crossfade> (*xfade.get(), &before, &xfade->get_state()));
+ _session->add_command (new MementoCommand<Crossfade> (*xfade.get(), &before, &xfade->get_state ()));
_session->commit_reversible_command ();
}
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index f2acf2e7a8..cef27660a6 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -1037,6 +1037,15 @@ RegionMoveDrag::finished_no_copy (
playlist->freeze ();
}
+ /* this movement may result in a crossfade being modified, so we need to get undo
+ data from the playlist as well as the region.
+ */
+
+ r = modified_playlists.insert (playlist);
+ if (r.second) {
+ playlist->clear_changes ();
+ }
+
rv->region()->set_position (where, (void*) this);
_editor->session()->add_command (new StatefulDiffCommand (rv->region()));
@@ -1172,7 +1181,12 @@ void
RegionMoveDrag::add_stateful_diff_commands_for_playlists (PlaylistSet const & playlists)
{
for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
- _editor->session()->add_command (new StatefulDiffCommand (*i));
+ StatefulDiffCommand* c = new StatefulDiffCommand (*i);
+ if (!c->empty()) {
+ _editor->session()->add_command (new StatefulDiffCommand (*i));
+ } else {
+ delete c;
+ }
}
}
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index f4c63531cc..d540134f17 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -2820,11 +2820,9 @@ Editor::separate_regions_between (const TimeSelection& ts)
/* pick up changes to existing regions */
- vector<StatefulDiffCommand*> cmds;
+ vector<Command*> cmds;
playlist->rdiff (cmds);
- for (vector<StatefulDiffCommand*>::iterator j = cmds.begin(); j != cmds.end(); ++j) {
- _session->add_command (*j);
- }
+ _session->add_commands (cmds);
/* pick up changes to the playlist itself (adds/removes)
*/
@@ -3773,11 +3771,9 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
playlist->add_region (r, start);
}
- vector<StatefulDiffCommand*> cmds;
+ vector<Command*> cmds;
playlist->rdiff (cmds);
- for (vector<StatefulDiffCommand*>::iterator j = cmds.begin(); j != cmds.end(); ++j) {
- _session->add_command (*j);
- }
+ _session->add_commands (cmds);
_session->add_command (new StatefulDiffCommand (playlist));
}
@@ -4492,13 +4488,10 @@ Editor::nudge_track (bool use_edit, bool forwards)
playlist->nudge_after (start, distance, forwards);
- vector<StatefulDiffCommand*> cmds;
+ vector<Command*> cmds;
playlist->rdiff (cmds);
-
- for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
- _session->add_command (*c);
- }
+ _session->add_commands (cmds);
_session->add_command (new StatefulDiffCommand (playlist));
}
@@ -6568,14 +6561,10 @@ Editor::insert_time (nframes64_t pos, nframes64_t frames, InsertTimeOption opt,
pl->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
- vector<StatefulDiffCommand*> cmds;
-
+ vector<Command*> cmds;
pl->rdiff (cmds);
-
- for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
- _session->add_command (*c);
- }
-
+ _session->add_commands (cmds);
+
_session->add_command (new StatefulDiffCommand (pl));
commit = true;
}
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index 391b08eac6..abc8101195 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -1339,13 +1339,10 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
if ((what_we_got = playlist->cut (time)) != 0) {
_editor.get_cut_buffer().add (what_we_got);
- vector<StatefulDiffCommand*> cmds;
-
+ vector<Command*> cmds;
playlist->rdiff (cmds);
-
- for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
- _session->add_command (*c);
- }
+ _session->add_commands (cmds);
+
_session->add_command (new StatefulDiffCommand (playlist));
}
break;
@@ -1357,13 +1354,10 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
case Clear:
if ((what_we_got = playlist->cut (time)) != 0) {
- vector<StatefulDiffCommand*> cmds;
-
+
+ vector<Command*> cmds;
playlist->rdiff (cmds);
-
- for (vector<StatefulDiffCommand*>::iterator c = cmds.begin(); c != cmds.end(); ++c) {
- _session->add_command (*c);
- }
+ _session->add_commands (cmds);
_session->add_command (new StatefulDiffCommand (playlist));
what_we_got->release ();
}
diff --git a/libs/ardour/ardour/audioplaylist.h b/libs/ardour/ardour/audioplaylist.h
index aee5fb3f64..f2d60bce8b 100644
--- a/libs/ardour/ardour/audioplaylist.h
+++ b/libs/ardour/ardour/audioplaylist.h
@@ -33,12 +33,39 @@ class Region;
class AudioRegion;
class Source;
+namespace Properties {
+ /* fake the type, since crossfades are handled by SequenceProperty which doesn't
+ care about such things.
+ */
+ extern PBD::PropertyDescriptor<bool> crossfades;
+}
+
+class AudioPlaylist;
+
+class CrossfadeListProperty : public PBD::SequenceProperty<std::list<boost::shared_ptr<Crossfade> > >
+{
+public:
+ CrossfadeListProperty (AudioPlaylist &);
+
+ void get_content_as_xml (boost::shared_ptr<Crossfade>, XMLNode &) const;
+ boost::shared_ptr<Crossfade> get_content_from_xml (XMLNode const &) const;
+
+private:
+ CrossfadeListProperty* clone () const;
+ CrossfadeListProperty* create () const;
+
+ friend class AudioPlaylist;
+ /* we live and die with our playlist, no lifetime management needed */
+ AudioPlaylist& _playlist;
+};
+
+
class AudioPlaylist : public ARDOUR::Playlist
{
- public:
+public:
typedef std::list<boost::shared_ptr<Crossfade> > Crossfades;
+ static void make_property_quarks ();
- public:
AudioPlaylist (Session&, const XMLNode&, bool hidden = false);
AudioPlaylist (Session&, std::string name, bool hidden = false);
AudioPlaylist (boost::shared_ptr<const AudioPlaylist>, std::string name, bool hidden = false);
@@ -59,6 +86,8 @@ class AudioPlaylist : public ARDOUR::Playlist
bool destroy_region (boost::shared_ptr<Region>);
+ void update (const CrossfadeListProperty::ChangeRecord &);
+
protected:
/* playlist "callbacks" */
@@ -72,7 +101,7 @@ class AudioPlaylist : public ARDOUR::Playlist
void remove_dependents (boost::shared_ptr<Region> region);
private:
- Crossfades _crossfades;
+ CrossfadeListProperty _crossfades;
Crossfades _pending_xfade_adds;
void crossfade_invalidated (boost::shared_ptr<Region>);
diff --git a/libs/ardour/ardour/crossfade.h b/libs/ardour/ardour/crossfade.h
index 4c75a0226b..2ce504eacf 100644
--- a/libs/ardour/ardour/crossfade.h
+++ b/libs/ardour/ardour/crossfade.h
@@ -73,7 +73,7 @@ class Crossfade : public ARDOUR::AudioRegion
/* the usual XML constructor */
- Crossfade (const Playlist&, XMLNode&);
+ Crossfade (const Playlist&, XMLNode const &);
virtual ~Crossfade();
static void make_property_quarks ();
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h
index 6473211126..a1a7bb752a 100644
--- a/libs/ardour/ardour/playlist.h
+++ b/libs/ardour/ardour/playlist.h
@@ -64,8 +64,8 @@ class RegionListProperty : public PBD::SequenceProperty<std::list<boost::shared_
RegionListProperty (Playlist&);
RegionListProperty* clone () const;
-
- boost::shared_ptr<Region> lookup_id (const PBD::ID& id) const;
+ void get_content_as_xml (boost::shared_ptr<Region>, XMLNode &) const;
+ boost::shared_ptr<Region> get_content_from_xml (XMLNode const &) const;
private:
RegionListProperty* create () const;
@@ -90,7 +90,7 @@ public:
void update (const RegionListProperty::ChangeRecord&);
void clear_owned_changes ();
- void rdiff (std::vector<PBD::StatefulDiffCommand*>&) const;
+ void rdiff (std::vector<Command*>&) const;
boost::shared_ptr<Region> region_by_id (const PBD::ID&) const;
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index c408714c94..75b9fb1831 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -680,6 +680,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
_current_trans.top()->add_command (cmd);
}
+ void add_commands (std::vector<Command*> const & cmds);
+
std::map<PBD::ID,PBD::StatefulDestructible*> registry;
// these commands are implemented in libs/ardour/session_command.cc
diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc
index cfc5a4028a..2ac3edff80 100644
--- a/libs/ardour/audio_playlist.cc
+++ b/libs/ardour/audio_playlist.cc
@@ -21,7 +21,6 @@
#include <cstdlib>
-
#include "ardour/types.h"
#include "ardour/debug.h"
#include "ardour/configuration.h"
@@ -38,14 +37,70 @@ using namespace ARDOUR;
using namespace std;
using namespace PBD;
+namespace ARDOUR {
+ namespace Properties {
+ PBD::PropertyDescriptor<bool> crossfades;
+ }
+}
+
+void
+AudioPlaylist::make_property_quarks ()
+{
+ Properties::crossfades.property_id = g_quark_from_static_string (X_("crossfades"));
+ DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for crossfades = %1\n", Properties::crossfades.property_id));
+}
+
+CrossfadeListProperty::CrossfadeListProperty (AudioPlaylist& pl)
+ : SequenceProperty<std::list<boost::shared_ptr<Crossfade> > > (Properties::crossfades.property_id, boost::bind (&AudioPlaylist::update, &pl, _1))
+ , _playlist (pl)
+{
+
+}
+
+
+CrossfadeListProperty *
+CrossfadeListProperty::create () const
+{
+ return new CrossfadeListProperty (_playlist);
+}
+
+CrossfadeListProperty *
+CrossfadeListProperty::clone () const
+{
+ return new CrossfadeListProperty (*this);
+}
+
+void
+CrossfadeListProperty::get_content_as_xml (boost::shared_ptr<Crossfade> xfade, XMLNode & node) const
+{
+ /* Crossfades are not written to any state when they are no
+ longer in use, so we must write their state here.
+ */
+
+ XMLNode& c = xfade->get_state ();
+ node.add_child_nocopy (c);
+}
+
+boost::shared_ptr<Crossfade>
+CrossfadeListProperty::get_content_from_xml (XMLNode const & node) const
+{
+ XMLNodeList const c = node.children ();
+ assert (c.size() == 1);
+ return boost::shared_ptr<Crossfade> (new Crossfade (_playlist, *c.front()));
+}
+
+
AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden)
: Playlist (session, node, DataType::AUDIO, hidden)
+ , _crossfades (*this)
{
#ifndef NDEBUG
const XMLProperty* prop = node.property("type");
assert(!prop || DataType(prop->value()) == DataType::AUDIO);
#endif
+ add_property (_crossfades);
+
in_set_state++;
set_state (node, Stateful::loading_state_version);
in_set_state--;
@@ -53,12 +108,17 @@ AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden
AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
: Playlist (session, name, DataType::AUDIO, hidden)
+ , _crossfades (*this)
{
+ add_property (_crossfades);
}
AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
: Playlist (other, name, hidden)
+ , _crossfades (*this)
{
+ add_property (_crossfades);
+
RegionList::const_iterator in_o = other->regions.begin();
RegionList::iterator in_n = regions.begin();
@@ -99,7 +159,10 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, stri
AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
: Playlist (other, start, cnt, name, hidden)
+ , _crossfades (*this)
{
+ add_property (_crossfades);
+
/* this constructor does NOT notify others (session) */
}
@@ -795,3 +858,13 @@ AudioPlaylist::foreach_crossfade (boost::function<void (boost::shared_ptr<Crossf
s (*i);
}
}
+
+void
+AudioPlaylist::update (const CrossfadeListProperty::ChangeRecord& change)
+{
+ for (CrossfadeListProperty::ChangeContainer::const_iterator i = change.added.begin(); i != change.added.end(); ++i) {
+ add_crossfade (*i);
+ }
+
+ /* don't remove crossfades here; they will be dealt with by the dependency code */
+}
diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc
index 601ea86f6b..eb1148fa2c 100644
--- a/libs/ardour/crossfade.cc
+++ b/libs/ardour/crossfade.cc
@@ -124,7 +124,7 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioR
initialize ();
}
-Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
+Crossfade::Crossfade (const Playlist& playlist, XMLNode const & node)
: AudioRegion (playlist.session(), 0, 0, "unnamed crossfade")
, CROSSFADE_DEFAULT_PROPERTIES
, _fade_in (Evoral::Parameter(FadeInAutomation)) // linear (gain coefficient) => -inf..+6dB
@@ -132,7 +132,7 @@ Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
{
boost::shared_ptr<Region> r;
- XMLProperty* prop;
+ XMLProperty const * prop;
LocaleGuard lg (X_("POSIX"));
/* we have to find the in/out regions before we can do anything else */
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index 2ecea550b5..0e12883d82 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -69,7 +69,7 @@
#include "ardour/debug.h"
#include "ardour/filesystem_paths.h"
#include "ardour/mix.h"
-#include "ardour/playlist.h"
+#include "ardour/audioplaylist.h"
#include "ardour/plugin_manager.h"
#include "ardour/process_thread.h"
#include "ardour/profile.h"
@@ -251,6 +251,7 @@ ARDOUR::init (bool use_vst, bool try_optimization)
AudioRegion::make_property_quarks ();
RouteGroup::make_property_quarks ();
Playlist::make_property_quarks ();
+ AudioPlaylist::make_property_quarks ();
/* this is a useful ready to use PropertyChange that many
things need to check. This avoids having to compose
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index 93a4d520e8..1b2d64baba 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -110,28 +110,46 @@ RegionListProperty::RegionListProperty (Playlist& pl)
: SequenceProperty<std::list<boost::shared_ptr<Region> > > (Properties::regions.property_id, boost::bind (&Playlist::update, &pl, _1))
, _playlist (pl)
{
+
}
-boost::shared_ptr<Region>
-RegionListProperty::lookup_id (const ID& id) const
+RegionListProperty *
+RegionListProperty::clone () const
{
- boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
-
- if (!ret) {
- ret = RegionFactory::region_by_id (id);
- }
+ return new RegionListProperty (*this);
+}
- return ret;
+RegionListProperty *
+RegionListProperty::create () const
+{
+ return new RegionListProperty (_playlist);
}
-RegionListProperty* RegionListProperty::clone () const
+void
+RegionListProperty::get_content_as_xml (boost::shared_ptr<Region> region, XMLNode & node) const
{
- return new RegionListProperty (*this);
+ /* All regions (even those which are deleted) have their state saved by other
+ code, so we can just store ID here.
+ */
+
+ node.add_property ("id", region->id().to_s ());
}
-RegionListProperty* RegionListProperty::create () const
+boost::shared_ptr<Region>
+RegionListProperty::get_content_from_xml (XMLNode const & node) const
{
- return new RegionListProperty (_playlist);
+ XMLProperty const * prop = node.property ("id");
+ assert (prop);
+
+ PBD::ID id (prop->value ());
+
+ boost::shared_ptr<Region> ret = _playlist.region_by_id (id);
+
+ if (!ret) {
+ ret = RegionFactory::region_by_id (id);
+ }
+
+ return ret;
}
Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
@@ -2100,7 +2118,7 @@ Playlist::mark_session_dirty ()
}
void
-Playlist::rdiff (vector<StatefulDiffCommand*>& cmds) const
+Playlist::rdiff (vector<Command*>& cmds) const
{
RegionLock rlock (const_cast<Playlist *> (this));
Stateful::rdiff (cmds);
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index 31282a210f..225b7c1909 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -2313,6 +2313,14 @@ Session::finish_reversible_command (UndoTransaction& ut)
}
void
+Session::add_commands (vector<Command*> const & cmds)
+{
+ for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
+ add_command (*i);
+ }
+}
+
+void
Session::begin_reversible_command(const string& name)
{
UndoTransaction* trans = new UndoTransaction();
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index 051054c9a7..f877f3c3be 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -286,7 +286,7 @@ def build(bld):
obj.includes = ['.', '../surfaces/control_protocol', '..']
obj.name = 'libardour'
obj.target = 'ardour'
- obj.uselib = 'GLIBMM GTHREAD AUBIO SIGCPP XML UUID JACK SNDFILE SAMPLERATE LRDF OSX COREAUDIO'
+ obj.uselib = 'GLIBMM GTHREAD AUBIO SIGCPP XML UUID JACK SNDFILE SAMPLERATE LRDF OSX COREAUDIO CURL DL'
obj.uselib_local = 'libpbd libmidipp libevoral libvamphost libvampplugin libtaglib librubberband libaudiographer'
obj.vnum = LIBARDOUR_LIB_VERSION
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
diff --git a/libs/pbd/pbd/command.h b/libs/pbd/pbd/command.h
index c6c3c8d3fd..db4d2bbd81 100644
--- a/libs/pbd/pbd/command.h
+++ b/libs/pbd/pbd/command.h
@@ -43,6 +43,10 @@ public:
virtual XMLNode &get_state();
virtual int set_state(const XMLNode&, int /*version*/) { /* noop */ return 0; }
+ virtual bool empty () const {
+ return false;
+ }
+
protected:
Command() {}
Command(const std::string& name) : _name(name) {}
diff --git a/libs/pbd/pbd/property_basics.h b/libs/pbd/pbd/property_basics.h
index cfae36df20..145e84abfc 100644
--- a/libs/pbd/pbd/property_basics.h
+++ b/libs/pbd/pbd/property_basics.h
@@ -103,7 +103,7 @@ public:
virtual void get_changes_as_properties (PropertyList& changes, Command *) const = 0;
/** Collect StatefulDiffCommands for changes to anything that we own */
- virtual void rdiff (std::vector<StatefulDiffCommand*> &) const {}
+ virtual void rdiff (std::vector<Command*> &) const {}
/** Look in an XML node written by get_changes_as_xml and, if XML from this property
* is found, create a property with the changes from the XML.
diff --git a/libs/pbd/pbd/sequence_property.h b/libs/pbd/pbd/sequence_property.h
index 5b37d7a0fc..4b494d4a8d 100644
--- a/libs/pbd/pbd/sequence_property.h
+++ b/libs/pbd/pbd/sequence_property.h
@@ -31,6 +31,7 @@
#include "pbd/id.h"
#include "pbd/property_basics.h"
#include "pbd/property_list.h"
+#include "pbd/stateful_diff_command.h"
namespace PBD {
@@ -80,8 +81,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);
}
@@ -97,18 +96,25 @@ class SequenceProperty : public PropertyBase
for (typename ChangeContainer::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) {
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);
@@ -191,11 +197,10 @@ 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);
+
+ typename Container::value_type v = get_content_from_xml (**j);
assert (v);
+
if ((*j)->name() == "Add") {
p->_changes.added.insert (v);
} else if ((*j)->name() == "Remove") {
@@ -206,13 +211,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);
@@ -255,6 +263,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);
diff --git a/libs/pbd/pbd/stateful.h b/libs/pbd/pbd/stateful.h
index 5c1f079bc6..735ffbdc4a 100644
--- a/libs/pbd/pbd/stateful.h
+++ b/libs/pbd/pbd/stateful.h
@@ -70,7 +70,7 @@ class Stateful {
void clear_changes ();
virtual void clear_owned_changes ();
PropertyList* get_changes_as_properties (Command *) const;
- virtual void rdiff (std::vector<StatefulDiffCommand*> &) const;
+ virtual void rdiff (std::vector<Command*> &) const;
bool changed() const;
/* create a property list from an XMLNode
diff --git a/libs/pbd/pbd/stateful_diff_command.h b/libs/pbd/pbd/stateful_diff_command.h
index 2d5c234d76..2a213d7a17 100644
--- a/libs/pbd/pbd/stateful_diff_command.h
+++ b/libs/pbd/pbd/stateful_diff_command.h
@@ -45,6 +45,8 @@ public:
XMLNode& get_state ();
+ bool empty () const;
+
private:
boost::weak_ptr<Stateful> _object; ///< the object in question
PBD::PropertyList* _changes; ///< property changes to execute this command
diff --git a/libs/pbd/stateful.cc b/libs/pbd/stateful.cc
index 8411dc4e60..e13a499e41 100644
--- a/libs/pbd/stateful.cc
+++ b/libs/pbd/stateful.cc
@@ -340,7 +340,7 @@ Stateful::property_factory (const XMLNode& history_node) const
}
void
-Stateful::rdiff (vector<StatefulDiffCommand*>& cmds) const
+Stateful::rdiff (vector<Command*>& cmds) const
{
for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
i->second->rdiff (cmds);
diff --git a/libs/pbd/stateful_diff_command.cc b/libs/pbd/stateful_diff_command.cc
index 93a215ad8a..0f456d2d6e 100644
--- a/libs/pbd/stateful_diff_command.cc
+++ b/libs/pbd/stateful_diff_command.cc
@@ -118,3 +118,9 @@ StatefulDiffCommand::get_state ()
return *node;
}
+
+bool
+StatefulDiffCommand::empty () const
+{
+ return _changes->empty();
+}