1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
5 * Copyright 2007 Novell, Inc. (http://www.novell.com)
7 * See the LICENSE file included with the distribution for details.
15 #include "resources.h"
16 #include "namescope.h"
21 // ResourceDictionaryIterator
24 ResourceDictionaryIterator::ResourceDictionaryIterator (ResourceDictionary
*resources
) : CollectionIterator (resources
)
30 ResourceDictionaryIterator::Init ()
32 g_hash_table_iter_init (&iter
, ((ResourceDictionary
*) collection
)->hash
);
38 ResourceDictionaryIterator::Next (MoonError
*err
)
40 if (generation
!= collection
->Generation ()) {
41 MoonError::FillIn (err
, MoonError::INVALID_OPERATION
, "The underlying collection has mutated");
45 if (!g_hash_table_iter_next (&iter
, &key
, &value
)) {
54 ResourceDictionaryIterator::Reset ()
56 if (generation
!= collection
->Generation ())
65 ResourceDictionaryIterator::GetCurrent (MoonError
*err
)
67 if (generation
!= collection
->Generation ()) {
68 MoonError::FillIn (err
, MoonError::INVALID_OPERATION
, "The underlying collection has mutated");
73 MoonError::FillIn (err
, MoonError::INVALID_OPERATION
, "Index out of bounds");
77 return (Value
*) value
;
81 ResourceDictionaryIterator::GetCurrentKey (MoonError
*err
)
83 if (generation
!= collection
->Generation ()) {
84 MoonError::FillIn (err
, MoonError::INVALID_OPERATION
, "The underlying collection has mutated");
89 MoonError::FillIn (err
, MoonError::INVALID_OPERATION
, "Index out of bounds");
93 return (const char *) key
;
102 free_value (Value
*value
)
107 ResourceDictionary::ResourceDictionary ()
109 SetObjectType (Type::RESOURCE_DICTIONARY
);
110 hash
= g_hash_table_new_full (g_str_hash
,
112 (GDestroyNotify
)g_free
,
113 (GDestroyNotify
)free_value
);
114 from_resource_dictionary_api
= false;
117 ResourceDictionary::~ResourceDictionary ()
119 g_hash_table_destroy (hash
);
123 ResourceDictionary::GetIterator ()
125 return new ResourceDictionaryIterator (this);
129 ResourceDictionary::CanAdd (Value
*value
)
135 ResourceDictionary::Add (const char* key
, Value
*value
)
138 return AddWithError (key
, value
, &err
);
142 ResourceDictionary::AddWithError (const char* key
, Value
*value
, MoonError
*error
)
145 MoonError::FillIn (error
, MoonError::ARGUMENT_NULL
, "key was null");
149 if (ContainsKey (key
)) {
150 MoonError::FillIn (error
, MoonError::ARGUMENT
, "An item with the same key has already been added");
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;
160 g_hash_table_insert (hash
, g_strdup (key
), v
);
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
);
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;
182 ResourceDictionary::ContainsKey (const char *key
)
190 return g_hash_table_lookup_extended (hash
, key
,
191 &orig_key
, &orig_value
);
195 ResourceDictionary::Remove (const char *key
)
200 /* check if the item exists first */
204 if (!g_hash_table_lookup_extended (hash
, key
,
205 &orig_key
, (gpointer
*)&orig_value
))
208 from_resource_dictionary_api
= true;
209 Collection::Remove (orig_value
);
210 from_resource_dictionary_api
= false;
212 g_hash_table_remove (hash
, key
);
218 ResourceDictionary::Set (const char *key
, Value
*value
)
220 /* check if the item exists first */
224 if (g_hash_table_lookup_extended (hash
, key
,
225 &orig_key
, (gpointer
*)&orig_value
)) {
229 Value
*v
= new Value (*value
);
231 from_resource_dictionary_api
= true;
232 Collection::Remove (orig_value
);
234 from_resource_dictionary_api
= false;
236 g_hash_table_replace (hash
, g_strdup (key
), v
);
242 ResourceDictionary::Get (const char *key
, bool *exists
)
247 *exists
= g_hash_table_lookup_extended (hash
, key
,
248 &orig_key
, (gpointer
*)&v
);
251 v
= GetFromMergedDictionaries (key
, exists
);
257 ResourceDictionary::GetFromMergedDictionaries (const char *key
, bool *exists
)
261 ResourceDictionaryCollection
*merged
= GetMergedDictionaries ();
268 CollectionIterator
*iter
= merged
->GetIterator ();
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
);
282 can_be_added_twice (Deployment
*deployment
, Value
*value
)
284 static Type::Kind twice_kinds
[] = {
285 Type::FRAMEWORKTEMPLATE
,
287 Type::STROKE_COLLECTION
,
288 Type::DRAWINGATTRIBUTES
,
291 Type::STYLUSPOINT_COLLECTION
,
297 for (int i
= 0; twice_kinds
[i
] != Type::INVALID
; i
++) {
298 if (Type::IsSubclassOf (deployment
, value
->GetKind (), twice_kinds
[i
]))
305 // XXX this was (mostly, except for the type check) c&p from DependencyObjectCollection
307 ResourceDictionary::AddedToCollection (Value
*value
, MoonError
*error
)
309 DependencyObject
*obj
= NULL
;
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 ()));
324 obj
->SetIsAttached (IsAttached ());
325 obj
->SetParent (this, error
);
329 obj
->AddPropertyChangeListener (this);
331 if (!from_resource_dictionary_api
) {
332 const char *key
= obj
->GetName();
335 MoonError::FillIn (error
, MoonError::ARGUMENT_NULL
, "key was null");
339 if (ContainsKey (key
)) {
340 MoonError::FillIn (error
, MoonError::ARGUMENT
, "An item with the same key has already been added");
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
));
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
);
367 remove_from_hash_by_value (gpointer key
,
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
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
396 ResourceDictionary::SetIsAttached (bool attached
)
398 if (IsAttached () == attached
)
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
416 ResourceDictionary::UnregisterAllNamesRootedAt (NameScope
*from_ns
)
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
433 ResourceDictionary::RegisterAllNamesRootedAt (NameScope
*to_ns
, MoonError
*error
)
437 for (guint i
= 0; i
< array
->len
; i
++) {
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
);