/*
- Copyright (C) 2010 Paul Davis
+ Copyright (C) 2010 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
#include "pbd/stateful_diff_command.h"
-#include "i18n.h"
+#include "pbd/property_list.h"
+#include "pbd/demangle.h"
+#include "pbd/i18n.h"
using namespace std;
using namespace PBD;
/** Create a new StatefulDiffCommand by examining the changes made to a Stateful
- * since the last time that clear_history was called on it.
+ * since the last time that clear_changes was called on it.
* @param s Stateful object.
*/
-StatefulDiffCommand::StatefulDiffCommand (Stateful* s)
- : _object (s)
+StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<StatefulDestructible> s)
+ : _object (s)
+ , _changes (0)
{
- pair<XMLNode *, XMLNode*> const p = s->diff ();
- _before = p.first;
- _after = p.second;
+ _changes = s->get_changes_as_properties (this);
+
+ /* if the stateful object that this command refers to goes away,
+ be sure to notify owners of this command.
+ */
+
+ s->DropReferences.connect_same_thread (*this, boost::bind (&Destructible::drop_references, this));
}
-StatefulDiffCommand::StatefulDiffCommand (Stateful* s, XMLNode const & n)
+StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<StatefulDestructible> s, XMLNode const & n)
: _object (s)
+ , _changes (0)
{
- _before = new XMLNode (*n.children().front());
- _after = new XMLNode (*n.children().back());
-}
+ const XMLNodeList& children (n.children());
+
+ for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
+ if ((*i)->name() == X_("Changes")) {
+ _changes = s->property_factory (**i);
+ }
+ }
+ assert (_changes != 0);
+
+ /* if the stateful object that this command refers to goes away,
+ be sure to notify owners of this command.
+ */
+
+ s->DropReferences.connect_same_thread (*this, boost::bind (&Destructible::drop_references, this));
+}
StatefulDiffCommand::~StatefulDiffCommand ()
{
- delete _before;
- delete _after;
+ drop_references ();
+
+ delete _changes;
}
void
StatefulDiffCommand::operator() ()
{
- _object->set_state (*_after, Stateful::current_state_version);
+ boost::shared_ptr<Stateful> s (_object.lock());
+
+ if (s) {
+ s->apply_changes (*_changes);
+ }
}
void
StatefulDiffCommand::undo ()
{
- _object->set_state (*_before, Stateful::current_state_version);
+ boost::shared_ptr<Stateful> s (_object.lock());
+
+ if (s) {
+ PropertyList p = *_changes;
+ p.invert ();
+ s->apply_changes (p);
+ }
}
XMLNode&
StatefulDiffCommand::get_state ()
{
+ boost::shared_ptr<Stateful> s (_object.lock());
+
+ if (!s) {
+ /* XXX should we throw? */
+ return * new XMLNode("");
+ }
+
XMLNode* node = new XMLNode (X_("StatefulDiffCommand"));
- node->add_property ("obj-id", _object->id().to_s());
- node->add_property ("type-name", typeid(*_object).name());
- node->add_child_copy (*_before);
- node->add_child_copy (*_after);
+ node->add_property ("obj-id", s->id().to_s());
+ node->add_property ("type-name", demangled_name (*s.get()));
+
+ XMLNode* changes = new XMLNode (X_("Changes"));
+
+ _changes->get_changes_as_xml (changes);
+
+ node->add_child_nocopy (*changes);
return *node;
}
+
+bool
+StatefulDiffCommand::empty () const
+{
+ return _changes->empty();
+}