summaryrefslogtreecommitdiff
path: root/libs/pbd/pbd/stateful.h
blob: fe2df931479429c6f7ab57347bfddf4146834fe2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
    Copyright (C) 2000-2010 Paul Davis

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef __pbd_stateful_h__
#define __pbd_stateful_h__

#include <string>
#include <list>
#include <cassert>

#include "pbd/libpbd_visibility.h"
#include "pbd/id.h"
#include "pbd/xml++.h"
#include "pbd/property_basics.h"
#include "pbd/signals.h"

class XMLNode;

namespace PBD {

namespace sys {
	class path;
}

class PropertyList;
class OwnedPropertyList;

/** Base class for objects with saveable and undoable state */
class LIBPBD_API Stateful {
  public:
	Stateful ();
	virtual ~Stateful();

	virtual XMLNode& get_state (void) = 0;
	virtual int set_state (const XMLNode&, int version) = 0;

	virtual bool apply_changes (PropertyBase const &);
	PropertyChange apply_changes (PropertyList const &);

	const OwnedPropertyList& properties() const { return *_properties; }

	void add_property (PropertyBase& s);

	/* Extra XML node: so that 3rd parties can attach state to the XMLNode
	   representing the state of this object.
	 */

	void add_extra_xml (XMLNode&);
	XMLNode *extra_xml (const std::string& str, bool add_if_missing = false);
	void save_extra_xml (const XMLNode&);

	const PBD::ID& id() const { return _id; }
	bool set_id (const XMLNode&);
	void set_id (const std::string&);
	void reset_id ();

	/* RAII structure to manage thread-local ID regeneration.
	 */
	struct ForceIDRegeneration {
		ForceIDRegeneration () {
			set_regenerate_xml_and_string_ids_in_this_thread (true);
		}
		~ForceIDRegeneration () {
			set_regenerate_xml_and_string_ids_in_this_thread (false);
		}
	};

	/* history management */

	void clear_changes ();
	virtual void clear_owned_changes ();
	PropertyList* get_changes_as_properties (Command *) const;
	virtual void rdiff (std::vector<Command*> &) const;
	bool changed() const;

	/* create a property list from an XMLNode */
	virtual PropertyList* property_factory (const XMLNode&) const;

	/* How stateful's notify of changes to their properties */
	PBD::Signal1<void,const PropertyChange&> PropertyChanged;

	static int current_state_version;
	static int loading_state_version;

	virtual void suspend_property_changes ();
	virtual void resume_property_changes ();

	bool property_changes_suspended() const { return g_atomic_int_get (const_cast<gint*>(&_stateful_frozen)) > 0; }

  protected:

	void add_instant_xml (XMLNode&, const std::string& directory_path);
	XMLNode *instant_xml (const std::string& str, const std::string& directory_path);
	void add_properties (XMLNode &);

	PropertyChange set_values (XMLNode const &);

	/* derived classes can implement this to do cross-checking
	   of property values after either a PropertyList or XML
	   driven property change.
	*/
	virtual void post_set (const PropertyChange&) { };

	XMLNode *_extra_xml;
	XMLNode *_instant_xml;
	PBD::PropertyChange     _pending_changed;
	Glib::Threads::Mutex _lock;

	std::string _xml_node_name; ///< name of node to use for this object in XML
	OwnedPropertyList* _properties;

	virtual void send_change (const PropertyChange&);
	/** derived classes can implement this in order to process a property change
	    within thaw() just before send_change() is called.
	*/
	virtual void mid_thaw (const PropertyChange&) { }

	bool regenerate_xml_or_string_ids () const;

  private:
	friend struct ForceIDRegeneration;
	static Glib::Threads::Private<bool> _regenerate_xml_or_string_ids;
	PBD::ID  _id;
	gint     _stateful_frozen;

	static void set_regenerate_xml_and_string_ids_in_this_thread (bool yn);
};

} // namespace PBD

#endif /* __pbd_stateful_h__ */