~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to libs/pbd/stateful.cc

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

Show diffs side-by-side

added added

removed removed

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