Make EnumWriter exceptions a bit more informative.
[ardour.git] / libs / pbd / stateful_diff_command.cc
1 /*
2     Copyright (C) 2010 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <iostream>
21
22 #include "pbd/stateful_diff_command.h"
23 #include "pbd/property_list.h"
24 #include "pbd/demangle.h"
25 #include "i18n.h"
26
27 using namespace std;
28 using namespace PBD;
29
30 /** Create a new StatefulDiffCommand by examining the changes made to a Stateful
31  *  since the last time that clear_changes was called on it.
32  *  @param s Stateful object.
33  */
34
35 StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<StatefulDestructible> s)
36         : _object (s)
37         , _changes (0)
38 {
39         _changes = s->get_changes_as_properties (this);
40
41         /* if the stateful object that this command refers to goes away,
42            be sure to notify owners of this command.
43         */
44
45         s->DropReferences.connect_same_thread (*this, boost::bind (&Destructible::drop_references, this));
46 }
47
48 StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<StatefulDestructible> s, XMLNode const & n)
49         : _object (s)
50         , _changes (0)
51 {
52         const XMLNodeList& children (n.children());
53
54         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
55                 if ((*i)->name() == X_("Changes")) {
56                         _changes = s->property_factory (**i);
57                 }
58         }
59
60         assert (_changes != 0);
61
62         /* if the stateful object that this command refers to goes away,
63            be sure to notify owners of this command.
64         */
65
66         s->DropReferences.connect_same_thread (*this, boost::bind (&Destructible::drop_references, this));
67 }
68
69 StatefulDiffCommand::~StatefulDiffCommand ()
70 {
71         drop_references ();
72
73         delete _changes;
74 }
75
76 void
77 StatefulDiffCommand::operator() ()
78 {
79         boost::shared_ptr<Stateful> s (_object.lock());
80
81         if (s) {
82                 s->apply_changes (*_changes);
83         }
84 }
85
86 void
87 StatefulDiffCommand::undo ()
88 {
89         boost::shared_ptr<Stateful> s (_object.lock());
90
91         if (s) {
92                 PropertyList p = *_changes;
93                 p.invert ();
94                 s->apply_changes (p);
95         }
96 }
97
98 XMLNode&
99 StatefulDiffCommand::get_state ()
100 {
101         boost::shared_ptr<Stateful> s (_object.lock());
102
103         if (!s) {
104                 /* XXX should we throw? */
105                 return * new XMLNode("");
106         }
107
108         XMLNode* node = new XMLNode (X_("StatefulDiffCommand"));
109
110         node->add_property ("obj-id", s->id().to_s());
111         node->add_property ("type-name", demangled_name (*s.get()));
112
113         XMLNode* changes = new XMLNode (X_("Changes"));
114
115         _changes->get_changes_as_xml (changes);
116         
117         node->add_child_nocopy (*changes);
118
119         return *node;
120 }
121
122 bool
123 StatefulDiffCommand::empty () const
124 {
125         return _changes->empty();
126 }