2 Copyright (C) 2000-2001 Paul Davis
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.
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.
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.
18 $Id: stateful.cc 629 2006-06-21 23:01:03Z paul $
23 #include "pbd/stateful.h"
24 #include "pbd/destructible.h"
25 #include "pbd/filesystem.h"
26 #include "pbd/xml++.h"
27 #include "pbd/error.h"
35 int Stateful::current_state_version = 0;
36 int Stateful::loading_state_version = 0;
44 Stateful::~Stateful ()
46 // Do not delete _extra_xml. The use of add_child_nocopy()
47 // means it needs to live on indefinately.
51 for (list<StateBase*>::iterator i = _states.begin(); i != _states.end(); ++i) {
57 Stateful::add_extra_xml (XMLNode& node)
59 if (_extra_xml == 0) {
60 _extra_xml = new XMLNode ("Extra");
63 _extra_xml->remove_nodes (node.name());
64 _extra_xml->add_child_nocopy (node);
68 Stateful::extra_xml (const string& str)
70 if (_extra_xml == 0) {
74 const XMLNodeList& nlist = _extra_xml->children();
75 XMLNodeConstIterator i;
77 for (i = nlist.begin(); i != nlist.end(); ++i) {
78 if ((*i)->name() == str) {
87 Stateful::add_instant_xml (XMLNode& node, const sys::path& directory_path)
89 sys::create_directories (directory_path); // may throw
91 if (_instant_xml == 0) {
92 _instant_xml = new XMLNode ("instant");
95 _instant_xml->remove_nodes_and_delete (node.name());
96 _instant_xml->add_child_copy (node);
98 sys::path instant_xml_path(directory_path);
100 instant_xml_path /= "instant.xml";
103 tree.set_filename(instant_xml_path.to_string());
105 /* Important: the destructor for an XMLTree deletes
106 all of its nodes, starting at _root. We therefore
107 cannot simply hand it our persistent _instant_xml
108 node as its _root, because we will lose it whenever
109 the Tree goes out of scope.
111 So instead, copy the _instant_xml node (which does
112 a deep copy), and hand that to the tree.
115 XMLNode* copy = new XMLNode (*_instant_xml);
116 tree.set_root (copy);
119 error << string_compose(_("Error: could not write %1"), instant_xml_path.to_string()) << endmsg;
124 Stateful::instant_xml (const string& str, const sys::path& directory_path)
126 if (_instant_xml == 0) {
128 sys::path instant_xml_path(directory_path);
129 instant_xml_path /= "instant.xml";
131 if (exists(instant_xml_path)) {
133 if (tree.read(instant_xml_path.to_string())) {
134 _instant_xml = new XMLNode(*(tree.root()));
136 warning << string_compose(_("Could not understand XML file %1"), instant_xml_path.to_string()) << endmsg;
144 const XMLNodeList& nlist = _instant_xml->children();
145 XMLNodeConstIterator i;
147 for (i = nlist.begin(); i != nlist.end(); ++i) {
148 if ((*i)->name() == str) {
156 /** Forget about any old state for this object */
158 Stateful::clear_history ()
160 for (list<StateBase*>::iterator i = _states.begin(); i != _states.end(); ++i) {
161 (*i)->clear_history ();
165 /** @return A pair of XMLNodes representing state that has changed since the last time clear_history
166 * was called on this object; the first is the state before, the second the state after.
168 * It is the caller's responsibility to delete the returned XMLNodes.
170 pair<XMLNode *, XMLNode *>
173 XMLNode* old = new XMLNode (_xml_node_name);
174 XMLNode* current = new XMLNode (_xml_node_name);
176 for (list<StateBase*>::iterator i = _states.begin(); i != _states.end(); ++i) {
177 (*i)->diff (old, current);
180 return make_pair (old, current);