Avoid the "deprecated or antiquated header" warning from g++ 4.3 by using <tr1/unorde...
[synfig.git] / synfig-core / trunk / src / synfig / node.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file node.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "node.h"
33 #include "nodebase.h"
34
35 #ifdef HASH_MAP_H
36 #include HASH_MAP_H
37 #else
38 #include <map>
39 #endif
40
41 #endif
42
43 /* === U S I N G =========================================================== */
44
45 using namespace std;
46 using namespace etl;
47 using namespace synfig;
48
49 /* === M A C R O S ========================================================= */
50
51 // About BE_FRUGAL_WITH_GUIDS
52 // If this macro is set, then a GUID will NOT
53 // be calculated until the first call to get_guid()
54 // This also means that the node doesn't get
55 // added to the database until get_guid() is called
56 // for the first time, or set_guid() is called.
57 // If it is expensive to calculate GUIDs, then
58 // this can improve performance a tad in
59 // some cases. Otherwise, it doesn't change
60 // much of anything.
61 #define BE_FRUGAL_WITH_GUIDS 1
62
63 #ifndef __sys_clock
64 #ifndef _WIN32
65 # include <time.h>
66 # define __sys_clock    ::clock
67 #else
68 # ifdef __GNUG__
69 #  include <time.h>
70 #  define __sys_clock   ::clock
71 # else
72 typedef int clock_t;
73 extern clock_t _clock();
74 #  define CLOCKS_PER_SEC 1000
75 #  define __sys_clock   _clock
76 # endif
77 #endif
78 #endif
79
80 /* === G L O B A L S ======================================================= */
81
82 #ifdef HASH_MAP_H
83 typedef HASH_MAP_CLASS<GUID,Node*,GUIDHash> GlobalNodeMap;
84 #else
85 typedef map<GUID,Node*> GlobalNodeMap;
86 #endif
87
88 static GlobalNodeMap* global_node_map_;
89
90 static GlobalNodeMap& global_node_map()
91 {
92         if(!global_node_map_)
93                 global_node_map_=new GlobalNodeMap;
94         return *global_node_map_;
95 }
96
97 /* === P R O C E D U R E S ================================================= */
98
99 synfig::Node*
100 synfig::find_node(const GUID& guid)
101 {
102         if(global_node_map().count(guid)==0)
103                 return 0;
104         return global_node_map()[guid];
105 }
106
107 static void
108 refresh_node(synfig::Node* node, GUID old_guid)
109 {
110         assert(global_node_map().count(old_guid));
111         global_node_map().erase(old_guid);
112         assert(!global_node_map().count(old_guid));
113         global_node_map()[node->get_guid()]=node;
114 }
115
116 /* === M E T H O D S ======================================================= */
117
118 #ifdef _DEBUG
119 const char *
120 TimePoint::c_str()const
121 {
122         return get_time().get_string().c_str();
123 }
124 #endif
125
126 void
127 TimePoint::absorb(const TimePoint& x)
128 {
129         if(get_guid()==x.get_guid())
130                 return;
131         set_guid(get_guid()^x.get_guid());
132
133         if(get_after()==INTERPOLATION_NIL)
134                 set_after(x.get_after());
135         if(get_before()==INTERPOLATION_NIL)
136                 set_before(x.get_before());
137
138         if(get_after()!=x.get_after() && x.get_after()!=INTERPOLATION_NIL)
139                 set_after(INTERPOLATION_UNDEFINED);
140         if(get_before()!=x.get_before() && x.get_before()!=INTERPOLATION_NIL)
141                 set_before(INTERPOLATION_UNDEFINED);
142 }
143
144 TimePointSet::iterator
145 TimePointSet::insert(const TimePoint& x)
146 {
147         iterator iter(find(x));
148         if(iter!=end())
149         {
150                 const_cast<TimePoint&>(*iter).absorb(x);
151                 return iter;
152         }
153         return std::set<TimePoint>::insert(x).first;
154 }
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 Node::Node():
171         guid_(0),
172         bchanged(true),
173         deleting_(false)
174 {
175 #ifndef BE_FRUGAL_WITH_GUIDS
176         guid_.make_unique();
177         assert(guid_);
178         assert(!global_node_map().count(guid_));
179         global_node_map()[guid_]=this;
180 #endif
181 }
182
183 Node::~Node()
184 {
185         begin_delete();
186
187         if(guid_)
188         {
189                 assert(global_node_map().count(guid_));
190                 global_node_map().erase(guid_);
191                 assert(!global_node_map().count(guid_));
192         }
193 }
194
195 void
196 Node::changed()
197 {
198         time_last_changed_=__sys_clock();
199         on_changed();
200 }
201
202
203 //! Gets the GUID for this value node
204 const GUID&
205 Node::get_guid()const
206 {
207 #ifdef BE_FRUGAL_WITH_GUIDS
208         if(!guid_)
209         {
210                 const_cast<GUID&>(guid_).make_unique();
211                 assert(guid_);
212                 assert(!global_node_map().count(guid_));
213                 global_node_map()[guid_]=const_cast<Node*>(this);
214         }
215 #endif
216
217         return guid_;
218 }
219
220 //! Sets the GUID for this value node
221 void
222 Node::set_guid(const GUID& x)
223 {
224         assert(x);
225
226 #ifdef BE_FRUGAL_WITH_GUIDS
227         if(!guid_)
228         {
229                 guid_=x;
230                 assert(!global_node_map().count(guid_));
231                 global_node_map()[guid_]=this;
232         }
233         else
234 #endif
235         if(guid_!=x)
236         {
237                 GUID oldguid(guid_);
238                 guid_=x;
239                 refresh_node(this, oldguid);
240                 on_guid_changed(oldguid);
241         }
242 }
243
244 int
245 Node::get_time_last_changed()const
246 {
247         return time_last_changed_;
248 }
249
250 void
251 Node::add_child(Node*x)
252 {
253         x->parent_set.insert(this);
254 }
255
256 void
257 Node::remove_child(Node*x)
258 {
259         if(x->parent_set.count(this)) x->parent_set.erase(this);
260 }
261
262 int
263 Node::parent_count()const
264 {
265         return parent_set.size();
266 }
267
268 const Node::time_set &
269 Node::get_times() const
270 {
271         if(bchanged)
272         {
273                 times.clear();
274                 get_times_vfunc(times);
275                 bchanged = false;
276         }
277
278         //set the output set...
279         return times;
280 }
281
282 void
283 Node::begin_delete()
284 {
285         if(!deleting_)
286         {
287                 deleting_=true; signal_deleted()();
288         }
289 }
290
291 void
292 Node::on_changed()
293 {
294         bchanged = true;
295         signal_changed()();
296
297         std::set<Node*>::iterator iter;
298         for(iter=parent_set.begin();iter!=parent_set.end();++iter)
299         {
300                 (*iter)->changed();
301         }
302 }
303
304 void
305 Node::on_guid_changed(GUID guid)
306 {
307         signal_guid_changed()(guid);
308 }