ardour
stateful.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000-2001 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  $Id: stateful.cc 629 2006-06-21 23:01:03Z paul $
19 */
20 
21 #ifdef COMPILER_MSVC
22 #include <io.h> // Microsoft's nearest equivalent to <unistd.h>
23 #else
24 #include <unistd.h>
25 #endif
26 
27 #include <glibmm/fileutils.h>
28 #include <glibmm/miscutils.h>
29 
30 #include "pbd/debug.h"
31 #include "pbd/stateful.h"
32 #include "pbd/property_list.h"
33 #include "pbd/properties.h"
34 #include "pbd/destructible.h"
35 #include "pbd/xml++.h"
36 #include "pbd/error.h"
37 
38 #include "i18n.h"
39 
40 using namespace std;
41 
42 namespace PBD {
43 
44 int Stateful::current_state_version = 0;
45 int Stateful::loading_state_version = 0;
46 
48  : _properties (new OwnedPropertyList)
49  , _stateful_frozen (0)
50 {
51  _extra_xml = 0;
52  _instant_xml = 0;
53 }
54 
56 {
57  delete _properties;
58 
59  // Do not delete _extra_xml. The use of add_child_nocopy()
60  // means it needs to live on indefinately.
61 
62  delete _instant_xml;
63 }
64 
65 void
67 {
68  if (_extra_xml == 0) {
69  _extra_xml = new XMLNode ("Extra");
70  }
71 
72  _extra_xml->remove_nodes (node.name());
74 }
75 
76 XMLNode *
77 Stateful::extra_xml (const string& str, bool add_if_missing)
78 {
79  XMLNode* node = 0;
80 
81  if (_extra_xml) {
82  node = _extra_xml->child (str.c_str());
83  }
84 
85  if (!node && add_if_missing) {
86  node = new XMLNode (str);
87  add_extra_xml (*node);
88  }
89 
90  return node;
91 }
92 
93 void
95 {
96  /* Looks for the child node called "Extra" and makes _extra_xml
97  point to a copy of it. Will delete any existing node pointed
98  to by _extra_xml if a new Extra node is found, but not
99  otherwise.
100  */
101 
102  const XMLNode* xtra = node.child ("Extra");
103 
104  if (xtra) {
105  delete _extra_xml;
106  _extra_xml = new XMLNode (*xtra);
107  }
108 }
109 
110 void
111 Stateful::add_instant_xml (XMLNode& node, const std::string& directory_path)
112 {
113  if (!Glib::file_test (directory_path, Glib::FILE_TEST_IS_DIR)) {
114  if (g_mkdir_with_parents (directory_path.c_str(), 0755) != 0) {
115  error << string_compose(_("Error: could not create directory %1"), directory_path) << endmsg;
116  return;
117  }
118  }
119 
120  if (_instant_xml == 0) {
121  _instant_xml = new XMLNode ("instant");
122  }
123 
126 
127  std::string instant_xml_path = Glib::build_filename (directory_path, "instant.xml");
128 
129  XMLTree tree;
130  tree.set_filename(instant_xml_path);
131 
132  /* Important: the destructor for an XMLTree deletes
133  all of its nodes, starting at _root. We therefore
134  cannot simply hand it our persistent _instant_xml
135  node as its _root, because we will lose it whenever
136  the Tree goes out of scope.
137 
138  So instead, copy the _instant_xml node (which does
139  a deep copy), and hand that to the tree.
140  */
141 
142  XMLNode* copy = new XMLNode (*_instant_xml);
143  tree.set_root (copy);
144 
145  if (!tree.write()) {
146  error << string_compose(_("Error: could not write %1"), instant_xml_path) << endmsg;
147  }
148 }
149 
150 XMLNode *
151 Stateful::instant_xml (const string& str, const std::string& directory_path)
152 {
153  if (_instant_xml == 0) {
154 
155  std::string instant_xml_path = Glib::build_filename (directory_path, "instant.xml");
156 
157  if (Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
158  XMLTree tree;
159  if (tree.read(instant_xml_path)) {
160  _instant_xml = new XMLNode(*(tree.root()));
161  } else {
162  warning << string_compose(_("Could not understand XML file %1"), instant_xml_path) << endmsg;
163  return 0;
164  }
165  } else {
166  return 0;
167  }
168  }
169 
170  const XMLNodeList& nlist = _instant_xml->children();
172 
173  for (i = nlist.begin(); i != nlist.end(); ++i) {
174  if ((*i)->name() == str) {
175  return (*i);
176  }
177  }
178 
179  return 0;
180 }
181 
183 void
185 {
186  for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
187  i->second->clear_changes ();
188  }
189 }
190 
191 PropertyList *
193 {
194  PropertyList* pl = new PropertyList;
195 
196  for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
197  i->second->get_changes_as_properties (*pl, cmd);
198  }
199 
200  return pl;
201 }
202 
210 {
211  PropertyChange c;
212 
213  for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
214  if (i->second->set_value (node)) {
215  c.add (i->first);
216  }
217  }
218 
219  post_set (c);
220 
221  return c;
222 }
223 
225 Stateful::apply_changes (const PropertyList& property_list)
226 {
227  PropertyChange c;
228  PropertyList::const_iterator p;
229 
230  DEBUG_TRACE (DEBUG::Stateful, string_compose ("Stateful %1 setting properties from list of %2\n", this, property_list.size()));
231 
232  for (PropertyList::const_iterator pp = property_list.begin(); pp != property_list.end(); ++pp) {
233  DEBUG_TRACE (DEBUG::Stateful, string_compose ("in plist: %1\n", pp->second->property_name()));
234  }
235 
236  for (PropertyList::const_iterator i = property_list.begin(); i != property_list.end(); ++i) {
237  if ((p = _properties->find (i->first)) != _properties->end()) {
238 
239  DEBUG_TRACE (
241  string_compose ("actually setting property %1 using %2\n", p->second->property_name(), i->second->property_name())
242  );
243 
244  if (apply_changes (*i->second)) {
245  c.add (i->first);
246  }
247  } else {
248  DEBUG_TRACE (DEBUG::Stateful, string_compose ("passed in property %1 not found in own property list\n",
249  i->second->property_name()));
250  }
251  }
252 
253  post_set (c);
254 
255  send_change (c);
256 
257  return c;
258 }
259 
263 void
265 {
266  for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
267  i->second->get_value (owner_state);
268  }
269 }
270 
271 void
273 {
274  _properties->add (s);
275 }
276 
277 void
279 {
280  if (what_changed.empty()) {
281  return;
282  }
283 
284  {
287  _pending_changed.add (what_changed);
288  return;
289  }
290  }
291 
292  PropertyChanged (what_changed);
293 }
294 
295 void
297 {
298  g_atomic_int_add (&_stateful_frozen, 1);
299 }
300 
301 void
303 {
304  PropertyChange what_changed;
305 
306  {
308 
309  if (property_changes_suspended() && g_atomic_int_dec_and_test (&_stateful_frozen) == FALSE) {
310  return;
311  }
312 
313  if (!_pending_changed.empty()) {
314  what_changed = _pending_changed;
315  _pending_changed.clear ();
316  }
317  }
318 
319  mid_thaw (what_changed);
320 
321  send_change (what_changed);
322 }
323 
324 bool
326 {
327  for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
328  if (i->second->changed()) {
329  return true;
330  }
331  }
332 
333  return false;
334 }
335 
336 bool
338 {
339  OwnedPropertyList::iterator i = _properties->find (prop.property_id());
340  if (i == _properties->end()) {
341  return false;
342  }
343 
344  i->second->apply_changes (&prop);
345  return true;
346 }
347 
349 Stateful::property_factory (const XMLNode& history_node) const
350 {
351  PropertyList* prop_list = new PropertyList;
352 
353  for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
354  PropertyBase* prop = i->second->clone_from_xml (history_node);
355 
356  if (prop) {
357  prop_list->add (prop);
358  }
359  }
360 
361  return prop_list;
362 }
363 
364 void
365 Stateful::rdiff (vector<Command*>& cmds) const
366 {
367  for (OwnedPropertyList::const_iterator i = _properties->begin(); i != _properties->end(); ++i) {
368  i->second->rdiff (cmds);
369  }
370 }
371 
372 void
374 {
375  for (OwnedPropertyList::iterator i = _properties->begin(); i != _properties->end(); ++i) {
376  i->second->clear_owned_changes ();
377  }
378 }
379 
380 bool
381 Stateful::set_id (const XMLNode& node)
382 {
383  const XMLProperty* prop;
384 
385  if ((prop = node.property ("id")) != 0) {
386  _id = prop->value ();
387  return true;
388  }
389 
390  return false;
391 }
392 
393 void
395 {
396  _id = ID ();
397 }
398 
399 void
400 Stateful::set_id (const string& str)
401 {
402  _id = str;
403 }
404 
405 } // namespace PBD
virtual void resume_property_changes()
Definition: stateful.cc:302
virtual ~Stateful()
Definition: stateful.cc:55
bool property_changes_suspended() const
Definition: stateful.h:95
virtual void send_change(const PropertyChange &)
Definition: stateful.cc:278
const std::string & value() const
Definition: xml++.h:159
PBD::Signal1< void, const PropertyChange & > PropertyChanged
Definition: stateful.h:87
void save_extra_xml(const XMLNode &)
Definition: stateful.cc:94
virtual void suspend_property_changes()
Definition: stateful.cc:296
bool write() const
Definition: xml++.cc:147
virtual PropertyList * property_factory(const XMLNode &) const
Definition: stateful.cc:349
const std::string & name() const
Definition: xml++.h:104
void add_property(PropertyBase &s)
Definition: stateful.cc:272
XMLNode * add_child_copy(const XMLNode &)
Definition: xml++.cc:363
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
LIBPBD_API Transmitter warning
PropertyList * get_changes_as_properties(Command *) const
Definition: stateful.cc:192
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
void add_properties(XMLNode &)
Definition: stateful.cc:264
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
virtual void rdiff(std::vector< Command * > &) const
Definition: stateful.cc:365
PropertyChange set_values(XMLNode const &)
Definition: stateful.cc:209
gint _stateful_frozen
Definition: stateful.h:127
Definition: xml++.h:55
OwnedPropertyList * _properties
Definition: stateful.h:117
Definition: id.h:32
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
#define _(Text)
Definition: i18n.h:11
XMLNode * _extra_xml
Definition: stateful.h:109
PropertyID property_id() const
virtual bool apply_changes(PropertyBase const &)
Definition: stateful.cc:337
XMLProperty * property(const char *)
Definition: xml++.cc:413
XMLNode * set_root(XMLNode *n)
Definition: xml++.h:63
XMLNode * root() const
Definition: xml++.h:62
void reset_id()
Definition: stateful.cc:394
bool set_id(const XMLNode &)
Definition: stateful.cc:381
bool read()
Definition: xml++.h:71
#define DEBUG_TRACE(bits, str)
Definition: debug.h:55
XMLNode * _instant_xml
Definition: stateful.h:112
virtual void post_set(const PropertyChange &)
Definition: stateful.h:109
const std::string & set_filename(const std::string &fn)
Definition: xml++.h:66
bool changed() const
Definition: stateful.cc:325
void remove_nodes(const std::string &)
Definition: xml++.cc:497
void add_instant_xml(XMLNode &, const std::string &directory_path)
Definition: stateful.cc:111
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
class LIBPBD_API PropertyList
virtual PropertyBase * clone_from_xml(const XMLNode &) const
PBD::ID _id
Definition: stateful.h:126
Definition: xml++.h:95
virtual void clear_owned_changes()
Definition: stateful.cc:373
Glib::Threads::Mutex _lock
Definition: stateful.h:114
XMLNode * extra_xml(const std::string &str, bool add_if_missing=false)
Definition: stateful.cc:77
Definition: debug.h:30
LIBPBD_API uint64_t Stateful
Definition: debug.cc:46
PBD::PropertyChange _pending_changed
Definition: stateful.h:113
XMLNode * child(const char *) const
Definition: xml++.cc:309
virtual void mid_thaw(const PropertyChange &)
Definition: stateful.h:123
void add_extra_xml(XMLNode &)
Definition: stateful.cc:66
void remove_nodes_and_delete(const std::string &)
XMLNode * instant_xml(const std::string &str, const std::string &directory_path)
Definition: stateful.cc:151
XMLNodeList::const_iterator XMLNodeConstIterator
Definition: xml++.h:49
void clear_changes()
Definition: stateful.cc:184
bool add(PropertyBase *prop)
void add(PropertyID id)
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
bool add(PropertyBase &p)