(1) remove most uses of MementoCommand for Playlist and Region (2) move frozen state...
[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 "i18n.h"
25
26 using namespace std;
27 using namespace PBD;
28
29 /** Create a new StatefulDiffCommand by examining the changes made to a Stateful
30  *  since the last time that clear_history was called on it.
31  *  @param s Stateful object.
32  */
33
34 StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<Stateful> s)
35         : _object (s)
36         , _before (new PropertyList)
37         , _after (new PropertyList)
38 {
39         s->diff (*_before, *_after);
40 }
41
42 StatefulDiffCommand::StatefulDiffCommand (boost::shared_ptr<Stateful> s, XMLNode const & n)
43         : _object (s)
44         , _before (0)
45         , _after (0)
46 {
47         const XMLNodeList& children (n.children());
48
49         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
50                 if ((*i)->name() == X_("Undo")) {
51                         _before = s->property_factory (**i);
52                 } else if ((*i)->name() == X_("Do")) {
53                         _after = s->property_factory (**i);
54                 }
55         }
56
57         assert (_before != 0);
58         assert (_after != 0);
59 }
60
61 StatefulDiffCommand::~StatefulDiffCommand ()
62 {
63         delete _before;
64         delete _after;
65 }
66
67 void
68 StatefulDiffCommand::operator() ()
69 {
70         boost::shared_ptr<Stateful> s (_object.lock());
71
72         if (s) {
73                 PropertyChange changed = s->set_properties (*_after);
74                 if (!changed.empty()) {
75                         s->PropertyChanged (changed);
76                 }
77         }
78 }
79
80 void
81 StatefulDiffCommand::undo ()
82 {
83         boost::shared_ptr<Stateful> s (_object.lock());
84
85         if (s) {
86                 std::cerr << "Undoing a stateful diff command\n";
87                 PropertyChange changed = s->set_properties (*_before);
88                 if (!changed.empty()) {
89                         std::cerr << "Sending changed\n";
90                         s->PropertyChanged (changed);
91                 }
92         }
93 }
94
95 XMLNode&
96 StatefulDiffCommand::get_state ()
97 {
98         boost::shared_ptr<Stateful> s (_object.lock());
99
100         if (!s) {
101                 /* XXX should we throw? */
102                 return * new XMLNode("");
103         }
104
105         XMLNode* node = new XMLNode (X_("StatefulDiffCommand"));
106
107         node->add_property ("obj-id", s->id().to_s());
108         node->add_property ("type-name", typeid(*s.get()).name());
109
110         XMLNode* before = new XMLNode (X_("Undo"));
111         XMLNode* after = new XMLNode (X_("Do"));
112
113         _before->add_history_state (before);
114         _after->add_history_state (after);
115         
116         node->add_child_nocopy (*before);
117         node->add_child_nocopy (*after);
118
119         return *node;
120 }