2009-12-07 Rolf Bjarne Kvinge <RKvinge@novell.com>
[moon.git] / src / resources.cpp
blob6f8e3c7fda4ea162ede8a5074ab48a1ed28c9043
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * resources.cpp
5 * Copyright 2007 Novell, Inc. (http://www.novell.com)
7 * See the LICENSE file included with the distribution for details.
8 *
9 */
11 #include <config.h>
12 #include <stdlib.h>
14 #include "runtime.h"
15 #include "resources.h"
16 #include "namescope.h"
17 #include "error.h"
21 // ResourceDictionaryIterator
24 ResourceDictionaryIterator::ResourceDictionaryIterator (ResourceDictionary *resources) : CollectionIterator (resources)
26 Init ();
29 void
30 ResourceDictionaryIterator::Init ()
32 g_hash_table_iter_init (&iter, ((ResourceDictionary *) collection)->hash);
33 value = NULL;
34 key = NULL;
37 bool
38 ResourceDictionaryIterator::Next (MoonError *err)
40 if (generation != collection->Generation ()) {
41 MoonError::FillIn (err, MoonError::INVALID_OPERATION, "The underlying collection has mutated");
42 return false;
45 if (!g_hash_table_iter_next (&iter, &key, &value)) {
46 key = value = NULL;
47 return false;
50 return true;
53 bool
54 ResourceDictionaryIterator::Reset ()
56 if (generation != collection->Generation ())
57 return false;
59 Init ();
61 return true;
64 Value *
65 ResourceDictionaryIterator::GetCurrent (MoonError *err)
67 if (generation != collection->Generation ()) {
68 MoonError::FillIn (err, MoonError::INVALID_OPERATION, "The underlying collection has mutated");
69 return NULL;
72 if (key == NULL) {
73 MoonError::FillIn (err, MoonError::INVALID_OPERATION, "Index out of bounds");
74 return NULL;
77 return (Value *) value;
80 const char *
81 ResourceDictionaryIterator::GetCurrentKey (MoonError *err)
83 if (generation != collection->Generation ()) {
84 MoonError::FillIn (err, MoonError::INVALID_OPERATION, "The underlying collection has mutated");
85 return NULL;
88 if (key == NULL) {
89 MoonError::FillIn (err, MoonError::INVALID_OPERATION, "Index out of bounds");
90 return NULL;
93 return (const char *) key;
98 // ResourceDictionary
101 static void
102 free_value (Value *value)
104 delete value;
107 ResourceDictionary::ResourceDictionary ()
109 SetObjectType (Type::RESOURCE_DICTIONARY);
110 hash = g_hash_table_new_full (g_str_hash,
111 g_str_equal,
112 (GDestroyNotify)g_free,
113 (GDestroyNotify)free_value);
114 from_resource_dictionary_api = false;
117 ResourceDictionary::~ResourceDictionary ()
119 g_hash_table_destroy (hash);
122 CollectionIterator *
123 ResourceDictionary::GetIterator ()
125 return new ResourceDictionaryIterator (this);
128 bool
129 ResourceDictionary::CanAdd (Value *value)
131 return true;
134 bool
135 ResourceDictionary::Add (const char* key, Value *value)
137 MoonError err;
138 return AddWithError (key, value, &err);
141 bool
142 ResourceDictionary::AddWithError (const char* key, Value *value, MoonError *error)
144 if (!key) {
145 MoonError::FillIn (error, MoonError::ARGUMENT_NULL, "key was null");
146 return false;
149 if (ContainsKey (key)) {
150 MoonError::FillIn (error, MoonError::ARGUMENT, "An item with the same key has already been added");
151 return false;
154 Value *v = new Value (*value);
156 from_resource_dictionary_api = true;
157 bool result = Collection::AddWithError (v, error) != -1;
158 from_resource_dictionary_api = false;
159 if (result)
160 g_hash_table_insert (hash, g_strdup (key), v);
161 return result;
164 bool
165 ResourceDictionary::Clear ()
167 #if GLIB_CHECK_VERSION(2,12,0)
168 if (glib_check_version (2,12,0))
169 g_hash_table_remove_all (hash);
170 else
171 #endif
172 g_hash_table_foreach_remove (hash, (GHRFunc) gtk_true, NULL);
174 from_resource_dictionary_api = true;
175 bool rv = Collection::Clear ();
176 from_resource_dictionary_api = false;
178 return rv;
181 bool
182 ResourceDictionary::ContainsKey (const char *key)
184 if (!key)
185 return false;
187 gpointer orig_value;
188 gpointer orig_key;
190 return g_hash_table_lookup_extended (hash, key,
191 &orig_key, &orig_value);
194 bool
195 ResourceDictionary::Remove (const char *key)
197 if (!key)
198 return false;
200 /* check if the item exists first */
201 Value* orig_value;
202 gpointer orig_key;
204 if (!g_hash_table_lookup_extended (hash, key,
205 &orig_key, (gpointer*)&orig_value))
206 return false;
208 from_resource_dictionary_api = true;
209 Collection::Remove (orig_value);
210 from_resource_dictionary_api = false;
212 g_hash_table_remove (hash, key);
214 return true;
217 bool
218 ResourceDictionary::Set (const char *key, Value *value)
220 /* check if the item exists first */
221 Value* orig_value;
222 gpointer orig_key;
224 if (g_hash_table_lookup_extended (hash, key,
225 &orig_key, (gpointer*)&orig_value)) {
226 return false;
229 Value *v = new Value (*value);
231 from_resource_dictionary_api = true;
232 Collection::Remove (orig_value);
233 Collection::Add (v);
234 from_resource_dictionary_api = false;
236 g_hash_table_replace (hash, g_strdup (key), v);
238 return true; // XXX
241 Value*
242 ResourceDictionary::Get (const char *key, bool *exists)
244 Value *v = NULL;
245 gpointer orig_key;
247 *exists = g_hash_table_lookup_extended (hash, key,
248 &orig_key, (gpointer*)&v);
250 if (!*exists)
251 v = GetFromMergedDictionaries (key, exists);
253 return v;
256 Value *
257 ResourceDictionary::GetFromMergedDictionaries (const char *key, bool *exists)
259 Value *v = NULL;
261 ResourceDictionaryCollection *merged = GetMergedDictionaries ();
263 if (!merged) {
264 *exists = false;
265 return NULL;
268 CollectionIterator *iter = merged->GetIterator ();
269 MoonError err;
271 while (iter->Next (&err) && !*exists) {
272 Value *dict_v = iter->GetCurrent (&err);
274 ResourceDictionary *dict = dict_v->AsResourceDictionary ();
275 v = dict->Get (key, exists);
278 return v;
281 static bool
282 can_be_added_twice (Deployment *deployment, Value *value)
284 static Type::Kind twice_kinds [] = {
285 Type::FRAMEWORKTEMPLATE,
286 Type::STYLE,
287 Type::STROKE_COLLECTION,
288 Type::DRAWINGATTRIBUTES,
289 Type::TRANSFORM,
290 Type::BRUSH,
291 Type::STYLUSPOINT_COLLECTION,
292 Type::BITMAPIMAGE,
293 Type::STROKE,
294 Type::INVALID
297 for (int i = 0; twice_kinds [i] != Type::INVALID; i++) {
298 if (Type::IsSubclassOf (deployment, value->GetKind (), twice_kinds [i]))
299 return true;
302 return false;
305 // XXX this was (mostly, except for the type check) c&p from DependencyObjectCollection
306 bool
307 ResourceDictionary::AddedToCollection (Value *value, MoonError *error)
309 DependencyObject *obj = NULL;
310 bool rv = false;
312 if (value->Is(GetDeployment (), Type::DEPENDENCY_OBJECT)) {
313 obj = value->AsDependencyObject ();
314 DependencyObject *parent = obj ? obj->GetParent () : NULL;
315 // Call SetSurface() /before/ setting the logical parent
316 // because Storyboard::SetSurface() needs to be able to
317 // distinguish between the two cases.
319 if (parent && !can_be_added_twice (GetDeployment (), value)) {
320 MoonError::FillIn (error, MoonError::INVALID_OPERATION, g_strdup_printf ("Element is already a child of another element. %s", Type::Find (GetDeployment (), value->GetKind ())->GetName ()));
321 return false;
324 obj->SetIsAttached (IsAttached ());
325 obj->SetParent (this, error);
326 if (error->number)
327 return false;
329 obj->AddPropertyChangeListener (this);
331 if (!from_resource_dictionary_api) {
332 const char *key = obj->GetName();
334 if (!key) {
335 MoonError::FillIn (error, MoonError::ARGUMENT_NULL, "key was null");
336 goto cleanup;
339 if (ContainsKey (key)) {
340 MoonError::FillIn (error, MoonError::ARGUMENT, "An item with the same key has already been added");
341 goto cleanup;
346 rv = Collection::AddedToCollection (value, error);
348 if (rv && !from_resource_dictionary_api && obj != NULL) {
349 const char *key = obj->GetName();
351 g_hash_table_insert (hash, g_strdup (key), new Value (obj));
354 cleanup:
355 if (!rv) {
356 if (obj) {
357 /* If we set the parent, but the object wasn't added to the collection, make sure we clear the parent */
358 printf ("ResourceDictionary::AddedToCollection (): not added, clearing parent from %p\n", obj);
359 obj->SetParent (NULL, NULL);
363 return rv;
366 static gboolean
367 remove_from_hash_by_value (gpointer key,
368 gpointer value,
369 gpointer user_data)
371 Value *v = (Value*)value;
372 DependencyObject *obj = (DependencyObject *) user_data;
373 return (v->GetKind () == obj->GetObjectType () && v->AsDependencyObject() == obj);
376 // XXX this was (mostly, except for the type check) c&p from DependencyObjectCollection
377 void
378 ResourceDictionary::RemovedFromCollection (Value *value)
380 if (value->Is (GetDeployment (), Type::DEPENDENCY_OBJECT)) {
381 DependencyObject *obj = value->AsDependencyObject ();
383 obj->RemovePropertyChangeListener (this);
384 obj->SetParent (NULL, NULL);
385 obj->SetIsAttached (false);
387 Collection::RemovedFromCollection (value);
389 if (!from_resource_dictionary_api)
390 g_hash_table_foreach_remove (hash, remove_from_hash_by_value, value->AsDependencyObject ());
394 // XXX this was (mostly, except for the type check) c&p from DependencyObjectCollection
395 void
396 ResourceDictionary::SetIsAttached (bool attached)
398 if (IsAttached () == attached)
399 return;
401 Value *value;
403 for (guint i = 0; i < array->len; i++) {
404 value = (Value *) array->pdata[i];
405 if (value->Is (GetDeployment (), Type::DEPENDENCY_OBJECT)) {
406 DependencyObject *obj = value->AsDependencyObject ();
407 obj->SetIsAttached (attached);
411 Collection::SetIsAttached (attached);
414 // XXX this was (mostly, except for the type check) c&p from DependencyObjectCollection
415 void
416 ResourceDictionary::UnregisterAllNamesRootedAt (NameScope *from_ns)
418 Value *value;
420 for (guint i = 0; i < array->len; i++) {
421 value = (Value *) array->pdata[i];
422 if (value->Is (GetDeployment (), Type::DEPENDENCY_OBJECT)) {
423 DependencyObject *obj = value->AsDependencyObject ();
424 obj->UnregisterAllNamesRootedAt (from_ns);
428 Collection::UnregisterAllNamesRootedAt (from_ns);
431 // XXX this was (mostly, except for the type check) c&p from DependencyObjectCollection
432 void
433 ResourceDictionary::RegisterAllNamesRootedAt (NameScope *to_ns, MoonError *error)
435 Value *value;
437 for (guint i = 0; i < array->len; i++) {
438 if (error->number)
439 break;
441 value = (Value *) array->pdata[i];
442 if (value->Is (GetDeployment (), Type::DEPENDENCY_OBJECT)) {
443 DependencyObject *obj = value->AsDependencyObject ();
444 obj->RegisterAllNamesRootedAt (to_ns, error);
448 Collection::RegisterAllNamesRootedAt (to_ns, error);