2009-12-07 Rolf Bjarne Kvinge <RKvinge@novell.com>
[moon.git] / src / type.cpp
blobc3b23829c99750069eff2b189ba0b1f46bd30bf4
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * type.cpp: Our type system
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
14 #include <config.h>
15 #include <string.h>
16 #include <stdlib.h>
18 #include "type.h"
19 #include "runtime.h"
20 #include "deployment.h"
21 #include "dependencyproperty.h"
24 * Type implementation
26 Type::Type (Deployment *deployment, Type::Kind type, Type::Kind parent, bool is_value_type, bool is_interface,
27 const char *name,
28 int event_count, int total_event_count, const char **events,
29 int interface_count, const Type::Kind *interfaces, bool ctor_visible,
30 create_inst_func *create_inst, const char *content_property)
32 this->type = type;
33 this->parent = parent;
34 this->is_value_type = is_value_type;
35 this->is_interface = is_interface;
36 this->name = name;
37 this->event_count = event_count;
38 this->total_event_count = total_event_count;
39 this->events = events;
40 this->ctor_visible = ctor_visible;
41 this->create_inst = create_inst;
42 this->content_property = content_property;
43 this->properties = NULL;
44 this->interface_count = interface_count;
45 if (this->interface_count) {
46 this->interfaces = new Type::Kind[interface_count];
47 memcpy (this->interfaces, interfaces, interface_count * sizeof (Type::Kind));
49 else {
50 this->interfaces = NULL;
52 this->deployment = deployment;
55 Type::~Type ()
57 if (properties) {
58 g_hash_table_destroy (properties);
59 properties = NULL;
62 delete [] interfaces;
65 int
66 Type::LookupEvent (const char *event_name)
68 Type *parent_type = Type::Find (deployment, parent);
69 int result;
71 if (events != NULL) {
72 for (int i = 0; events [i] != NULL; i++) {
73 if (!g_ascii_strcasecmp (events [i], event_name))
74 return i + (parent_type == NULL ? 0 : parent_type->total_event_count);
78 if (parent == Type::INVALID || parent_type == NULL) {
79 #if SANITY
80 printf ("Event lookup of event '%s' in type '%s' failed.\n", event_name, name);
81 #endif
82 return -1;
85 result = parent_type->LookupEvent (event_name);
87 #if SANITY
88 if (result == -1)
89 printf ("Event lookup of event '%s' in (more exactly) type '%s' failed.\n", event_name, name);
90 #endif
92 return result;
95 bool
96 Type::IsSubclassOf (Deployment *deployment, Type::Kind type, Type::Kind super)
98 return deployment->GetTypes ()->IsSubclassOf (type, super);
101 bool
102 Type::IsSubclassOf (Type::Kind super)
104 return deployment->GetTypes ()->IsSubclassOf (type, super);
107 #if SANITY || DEBUG
108 bool
109 Types::IsSubclassOrSuperclassOf (Type::Kind unknown, Type::Kind known)
111 return IsSubclassOf(unknown, known) || IsSubclassOf (known, unknown);
114 bool
115 Types::IsSubclassOrSuperclassOf (Types *arg, Type::Kind unknown, Type::Kind known)
117 Types *types = arg == NULL ? Deployment::GetCurrent ()->GetTypes () : arg;
118 return types->IsSubclassOf(unknown, known) || types->IsSubclassOf (known, unknown);
120 #endif
122 bool
123 Types::IsSubclassOf (Type::Kind type, Type::Kind super)
125 Type *t;
126 Type::Kind parent;
128 if (type == Type::INVALID)
129 return false;
131 if (type == super)
132 return true;
134 t = Find (type);
136 g_return_val_if_fail (t != NULL, false);
138 do {
139 parent = t->parent;
141 if (parent == super)
142 return true;
144 if (parent == Type::INVALID)
145 return false;
147 t = Find (parent);
149 if (t == NULL)
150 return false;
151 } while (true);
153 return false;
156 bool
157 Type::IsAssignableFrom (Type::Kind type)
159 return deployment->GetTypes ()->IsAssignableFrom (GetKind (), type);
161 bool
162 Type::IsAssignableFrom (Deployment *deployment, Type::Kind destination, Type::Kind type)
164 return deployment->GetTypes ()->IsAssignableFrom (destination, type);
167 bool
168 Types::IsAssignableFrom (Type::Kind destination, Type::Kind type)
170 if (destination == type)
171 return true;
173 if (IsSubclassOf (type, destination))
174 return true;
176 // more expensive.. interface checks
177 Type *destination_type = Find (destination);
178 if (!destination_type->IsInterface())
179 return false;
181 Type *type_type = Find (type);
182 while (type_type && type_type->GetKind() != Type::INVALID) {
183 for (int i = 0; i < type_type->GetInterfaceCount(); i ++) {
184 // should this be IsAssignableFrom instead of ==? ugh
185 if (type_type->GetInterface(i) == destination)
186 return true;
188 type_type = Find (type_type->parent);
191 return false;
194 Type *
195 Type::Find (Deployment *deployment, const char *name)
197 return deployment->GetTypes ()->Find (name);
200 Type *
201 Type::Find (Deployment *deployment, const char *name, bool ignore_case)
203 return deployment->GetTypes ()->Find (name, ignore_case);
206 Type *
207 Type::Find (Deployment *deployment, Type::Kind type)
209 if (type < Type::INVALID || type == Type::LASTTYPE)
210 return NULL;
212 return deployment->GetTypes ()->Find (type);
215 DependencyObject *
216 Type::CreateInstance ()
218 if (!create_inst) {
219 g_warning ("Unable to create an instance of type: %s\n", name);
220 return NULL;
223 return create_inst ();
226 const char *
227 Type::GetContentPropertyName ()
229 Type *parent_type;
231 if (type == INVALID)
232 return NULL;
234 if (content_property)
235 return content_property;
237 parent_type = Find (deployment, parent);
239 if (parent_type == NULL)
240 return NULL;
242 return parent_type->GetContentPropertyName ();
245 DependencyProperty *
246 Type::LookupProperty (const char *name)
248 DependencyProperty *property = NULL;
250 g_return_val_if_fail (name != NULL, NULL);
252 if (properties != NULL) {
253 char *key = g_ascii_strdown (name, -1);
254 property = (DependencyProperty*) g_hash_table_lookup (properties, key);
255 g_free (key);
257 if (property)
258 return property;
261 return NULL;
264 void
265 Type::AddProperty (DependencyProperty *property)
267 DependencyProperty *existing = NULL;
269 g_return_if_fail (property != NULL);
271 if (properties == NULL) {
272 properties = g_hash_table_new (g_str_hash, g_str_equal);
273 } else {
274 existing = (DependencyProperty *) g_hash_table_lookup (properties, property->GetHashKey ());
277 if (existing == NULL || existing->IsCustom ()) {
278 // Allow overwriting of custom properties
279 g_hash_table_insert (properties, (gpointer) property->GetHashKey (), property);
280 } else {
281 g_warning ("Type::AddProperty (): Trying to register the property '%s' (of type %s) in the owner type '%s', and there already is a property registered on that type with the same name.",
282 property->GetName (), Type::Find (deployment, property->GetPropertyType ())->GetName(), GetName());
286 Type *
287 Type::GetParentType ()
289 if (parent == Type::INVALID)
290 return NULL;
292 return deployment->GetTypes ()->Find (parent);
295 static void
296 property_add (gpointer key, gpointer value, gpointer user_data)
298 g_hash_table_insert ((GHashTable *) user_data, key, value);
301 GHashTable *
302 Type::CopyProperties (bool inherited)
304 GHashTable *props = g_hash_table_new (g_str_hash, g_str_equal);
305 Type *type = this;
307 do {
308 if (type->properties)
309 g_hash_table_foreach (type->properties, property_add, props);
311 if (!inherited || !type->HasParent ())
312 break;
314 type = type->GetParentType ();
315 } while (type);
317 return props;
320 bool
321 type_get_value_type (Type::Kind type)
323 Type *t = Type::Find (Deployment::GetCurrent (), type);
325 if (t == NULL)
326 return false;
328 return t->IsValueType ();
331 bool
332 type_is_dependency_object (Type::Kind type)
334 return Type::IsSubclassOf (Deployment::GetCurrent (), type, Type::DEPENDENCY_OBJECT);
337 DependencyObject *
338 type_create_instance (Type *type)
340 if (!type) {
341 g_warning ("Unable to create instance of type %p.", type);
342 return NULL;
345 return type->CreateInstance ();
348 DependencyObject *
349 type_create_instance_from_kind (Type::Kind kind)
351 Type *t = Type::Find (Deployment::GetCurrent (), kind);
353 if (t == NULL) {
354 g_warning ("Unable to create instance of type %d. Type not found.", kind);
355 return NULL;
358 return t->CreateInstance ();
362 * Types
365 Types::Types ()
367 //printf ("Types::Types (). this: %p\n", this);
368 types.SetCount ((int) Type::LASTTYPE + 1);
369 RegisterNativeTypes ();
372 void
373 Types::Initialize ()
375 RegisterNativeProperties ();
378 void
379 Types::DeleteProperties ()
381 /* this can't be done in the destructor, since deleting the properties might end up accessing the types */
382 for (int i = 0; i < properties.GetCount (); i++)
383 delete (DependencyProperty *) properties [i];
384 properties.SetCount (0);
387 void
388 Types::Dispose ()
390 for (int i = 0; i < properties.GetCount (); i++)
391 ((DependencyProperty *) properties [i])->Dispose ();
394 Types::~Types ()
396 for (int i = 0; i < types.GetCount (); i++)
397 delete (Type *) types [i];
400 void
401 Types::AddProperty (DependencyProperty *property)
403 Type *type;
405 g_return_if_fail (property != NULL);
407 type = Find (property->GetOwnerType ());
409 g_return_if_fail (type != NULL);
411 property->SetId (properties.Add (property));
412 type->AddProperty (property);
415 DependencyProperty *
416 Types::GetProperty (int id)
418 g_return_val_if_fail (properties.GetCount () > id, NULL);
419 return (DependencyProperty *) properties [id];
422 Type *
423 Types::Find (const char *name)
425 return Types::Find (name, true);
428 Type *
429 Types::Find (const char *name, bool ignore_case)
431 Type *t;
433 for (int i = 1; i < types.GetCount (); i++) { // 0 = INVALID, shouldn't compare against that
434 if (i == Type::LASTTYPE)
435 continue;
437 t = (Type *) types [i];
438 if ((ignore_case && !g_ascii_strcasecmp (t->GetName (), name)) || !strcmp (t->GetName (), name))
439 return t;
442 return NULL;
445 Type::Kind
446 Types::RegisterType (const char *name, void *gc_handle, Type::Kind parent, bool is_interface, bool ctor_visible, Type::Kind* interfaces, int interface_count)
448 Type *type = new Type (Deployment::GetCurrent (), Type::INVALID, parent, false, is_interface, g_strdup (name), 0, Find (parent)->GetEventCount (), NULL, interface_count, interfaces, ctor_visible, NULL, NULL);
450 // printf ("Types::RegisterType (%s, %p, %i (%s)). this: %p, size: %i, count: %i\n", name, gc_handle, parent, Type::Find (this, parent) ? Type::Find (this, parent)->name : NULL, this, size, count);
452 type->SetKind ((Type::Kind) types.Add (type));
454 return type->GetKind ();