Added a Max Core Property Index so that a range can be defined in toolkit
[platform/core/uifw/dali-core.git] / dali / internal / event / common / object-impl.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/common/object-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/debug.h>
26 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
27 #include <dali/internal/update/common/animatable-property.h>
28 #include <dali/internal/update/common/property-owner-messages.h>
29 #include <dali/internal/update/common/uniform-map.h>
30 #include <dali/internal/event/animation/constraint-impl.h>
31 #include <dali/internal/event/common/stage-impl.h>
32 #include <dali/internal/event/common/property-notification-impl.h>
33 #include <dali/internal/event/common/type-registry-impl.h>
34
35 using Dali::Internal::SceneGraph::AnimatableProperty;
36 using Dali::Internal::SceneGraph::PropertyBase;
37
38 namespace Dali
39 {
40
41 namespace Internal
42 {
43
44 namespace // unnamed namespace
45 {
46 const int SUPPORTED_CAPABILITIES = Dali::Handle::DYNAMIC_PROPERTIES;  // Object provides this capability
47 typedef Dali::Vector<Object::Observer*>::Iterator ObserverIter;
48 typedef Dali::Vector<Object::Observer*>::ConstIterator ConstObserverIter;
49
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_OBJECT" );
52 #endif
53
54
55 } // unnamed namespace
56
57 Object::Object()
58 : mEventThreadServices( *Stage::GetCurrent() ),
59   mTypeInfo( NULL ),
60   mConstraints( NULL ),
61   mPropertyNotifications( NULL )
62 {
63 }
64
65 void Object::AddObserver(Observer& observer)
66 {
67   // make sure an observer doesn't observe the same object twice
68   // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ObjectDestroyed()
69   DALI_ASSERT_DEBUG( mObservers.End() == std::find( mObservers.Begin(), mObservers.End(), &observer));
70
71   mObservers.PushBack( &observer );
72 }
73
74 void Object::RemoveObserver(Observer& observer)
75 {
76   // Find the observer...
77   const ConstObserverIter endIter =  mObservers.End();
78   for( ObserverIter iter = mObservers.Begin(); iter != endIter; ++iter)
79   {
80     if( (*iter) == &observer)
81     {
82       mObservers.Erase( iter );
83       break;
84     }
85   }
86   DALI_ASSERT_DEBUG(endIter != mObservers.End());
87 }
88
89 void Object::OnSceneObjectAdd()
90 {
91   // Notification for observers
92   for( ConstObserverIter iter = mObservers.Begin(),  endIter =  mObservers.End(); iter != endIter; ++iter)
93   {
94     (*iter)->SceneObjectAdded(*this);
95   }
96
97   // enable property notifications in scene graph
98   EnablePropertyNotifications();
99 }
100
101 void Object::OnSceneObjectRemove()
102 {
103   // Notification for observers
104   for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter )
105   {
106     (*iter)->SceneObjectRemoved(*this);
107   }
108
109   // disable property notifications in scene graph
110   DisablePropertyNotifications();
111 }
112
113 int Object::GetPropertyComponentIndex( Property::Index index ) const
114 {
115   int componentIndex = Property::INVALID_COMPONENT_INDEX;
116
117   const TypeInfo* typeInfo( GetTypeInfo() );
118   if ( typeInfo )
119   {
120     componentIndex = typeInfo->GetComponentIndex(index);
121   }
122
123   // For animatable property, check whether it is registered already and register it if not yet.
124   if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) && ( NULL == RegisterAnimatableProperty(index) ) )
125   {
126     componentIndex = Property::INVALID_COMPONENT_INDEX;
127   }
128
129   return componentIndex;
130 }
131
132 bool Object::Supports( Capability capability ) const
133 {
134   return (capability & SUPPORTED_CAPABILITIES);
135 }
136
137 unsigned int Object::GetPropertyCount() const
138 {
139   unsigned int count = GetDefaultPropertyCount();
140
141   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Default Properties: %d\n", count );
142
143   const TypeInfo* typeInfo( GetTypeInfo() );
144   if ( typeInfo )
145   {
146     unsigned int manual( typeInfo->GetPropertyCount() );
147     count += manual;
148
149     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Manual Properties:  %d\n", manual );
150   }
151
152   unsigned int custom( mCustomProperties.Count() );
153   count += custom;
154   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties:  %d\n", custom );
155
156   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties:   %d\n", count );
157
158   return count;
159 }
160
161 std::string Object::GetPropertyName( Property::Index index ) const
162 {
163   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
164
165   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
166   {
167     std::string string;
168
169     const char * propertyName = GetDefaultPropertyName( index );
170     if( propertyName )
171     {
172       string = propertyName;
173     }
174     return string;
175   }
176
177   if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
178     || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
179   {
180     const TypeInfo* typeInfo( GetTypeInfo() );
181     if ( typeInfo )
182     {
183       return typeInfo->GetPropertyName( index );
184     }
185     else
186     {
187       DALI_ASSERT_ALWAYS( ! "Property index is invalid" );
188     }
189   }
190
191   CustomPropertyMetadata* custom = FindCustomProperty( index );
192   if( custom )
193   {
194     return custom->name;
195   }
196   return "";
197 }
198
199 Property::Index Object::GetPropertyIndex(const std::string& name) const
200 {
201   Property::Index index = GetDefaultPropertyIndex( name );
202
203   if(index == Property::INVALID_INDEX)
204   {
205     const TypeInfo* typeInfo( GetTypeInfo() );
206     if ( typeInfo )
207     {
208       index = typeInfo->GetPropertyIndex( name );
209       if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
210       {
211         // check whether the animatable property is registered already, if not then register one.
212         if ( NULL == RegisterAnimatableProperty(index) )
213         {
214           index = Property::INVALID_INDEX;
215         }
216       }
217     }
218   }
219
220   if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
221   {
222     Property::Index count = PROPERTY_CUSTOM_START_INDEX;
223     const PropertyMetadataLookup::ConstIterator end = mCustomProperties.End();
224     for( PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
225     {
226       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
227       if ( custom->name == name )
228       {
229         if ( custom->childPropertyIndex != Property::INVALID_INDEX )
230         {
231           // If it is a child property, return the child property index
232           index = custom->childPropertyIndex;
233         }
234         else
235         {
236           index = count;
237         }
238         break;
239       }
240     }
241   }
242
243   return index;
244 }
245
246 bool Object::IsPropertyWritable( Property::Index index ) const
247 {
248   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
249
250   bool writable = false;
251
252   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
253   {
254     writable = IsDefaultPropertyWritable( index );
255   }
256   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
257   {
258     const TypeInfo* typeInfo( GetTypeInfo() );
259     if ( typeInfo )
260     {
261       writable = typeInfo->IsPropertyWritable( index );
262     }
263     else
264     {
265       DALI_ASSERT_ALWAYS( ! "Invalid property index" );
266     }
267   }
268   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
269   {
270     // Type Registry scene-graph properties are writable.
271     writable = true;
272   }
273   else
274   {
275     CustomPropertyMetadata* custom = FindCustomProperty( index );
276     if( custom )
277     {
278       writable = custom->IsWritable();
279     }
280   }
281
282   return writable;
283 }
284
285 bool Object::IsPropertyAnimatable( Property::Index index ) const
286 {
287   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
288
289   bool animatable = false;
290
291   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
292   {
293     animatable = IsDefaultPropertyAnimatable( index );
294   }
295   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
296   {
297     // Type Registry event-thread only properties are not animatable.
298     animatable = false;
299   }
300   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
301   {
302     // Type Registry scene-graph properties are animatable.
303     animatable = true;
304   }
305   else
306   {
307     CustomPropertyMetadata* custom = FindCustomProperty( index );
308     if( custom )
309     {
310       animatable = custom->IsAnimatable();
311     }
312   }
313
314   return animatable;
315 }
316
317 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
318 {
319   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
320
321   bool isConstraintInput = false;
322
323   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
324   {
325     isConstraintInput = IsDefaultPropertyAConstraintInput( index );
326   }
327   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
328   {
329     // Type Registry event-thread only properties cannot be used as an input to a constraint.
330     isConstraintInput = false;
331   }
332   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
333   {
334     // scene graph properties can be used as input to a constraint.
335     isConstraintInput = true;
336   }
337   else
338   {
339     CustomPropertyMetadata* custom = FindCustomProperty( index );
340     if( custom )
341     {
342       // ... custom properties can be used as input to a constraint.
343       isConstraintInput = true;
344     }
345   }
346
347   return isConstraintInput;
348 }
349
350 Property::Type Object::GetPropertyType( Property::Index index ) const
351 {
352   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
353
354   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
355   {
356     return GetDefaultPropertyType( index );
357   }
358
359   if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
360     || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
361   {
362     const TypeInfo* typeInfo( GetTypeInfo() );
363     if ( typeInfo )
364     {
365       return typeInfo->GetPropertyType( index );
366     }
367     else
368     {
369       DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
370     }
371   }
372
373   CustomPropertyMetadata* custom = FindCustomProperty( index );
374   if( custom )
375   {
376     return custom->GetType();
377   }
378
379   return Property::NONE;
380 }
381
382 void Object::SetProperty( Property::Index index, const Property::Value& propertyValue )
383 {
384   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
385
386   bool propertySet( true );
387
388   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
389   {
390     SetDefaultProperty( index, propertyValue );
391   }
392   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
393   {
394     const TypeInfo* typeInfo( GetTypeInfo() );
395     if ( typeInfo )
396     {
397       typeInfo->SetProperty( this, index, propertyValue );
398     }
399     else
400     {
401       DALI_LOG_ERROR("Cannot find property index\n");
402       propertySet = false;
403     }
404   }
405   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
406   {
407     // check whether the animatable property is registered already, if not then register one.
408     AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
409     if(!animatableProperty)
410     {
411       DALI_LOG_ERROR("Cannot find property index\n");
412       propertySet = false;
413     }
414     else
415     {
416       // set the scene graph property value
417       SetSceneGraphProperty( index, *animatableProperty, propertyValue );
418     }
419   }
420   else
421   {
422     CustomPropertyMetadata* custom = FindCustomProperty( index );
423
424     if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
425     {
426       if( !custom )
427       {
428         // If the child property is not registered yet, register it.
429         custom = new CustomPropertyMetadata( "", propertyValue, Property::READ_WRITE );
430         mCustomProperties.PushBack( custom );
431       }
432
433       custom->childPropertyIndex = index;
434
435       // Resolve name for the child property
436       Object* parent = GetParentObject();
437       if( parent )
438       {
439         const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
440         if( parentTypeInfo )
441         {
442           custom->name = parentTypeInfo->GetChildPropertyName( index );
443         }
444       }
445     }
446
447     if( custom )
448     {
449       if( custom->IsAnimatable() )
450       {
451         // set the scene graph property value
452         SetSceneGraphProperty( index, *custom, propertyValue );
453       }
454       else if( custom->IsWritable() )
455       {
456         custom->value = propertyValue;
457       }
458       else
459       {
460         // trying to set value on read only property is no-op
461         propertySet = false;
462       }
463     }
464     else
465     {
466       DALI_LOG_ERROR("Invalid property index\n");
467       propertySet = false;
468     }
469   }
470
471   // Let derived classes know that a property has been set
472   // TODO: We should not call this for read-only properties, SetDefaultProperty() && TypeInfo::SetProperty() should return a bool, which would be true if the property is set
473   if ( propertySet )
474   {
475     OnPropertySet(index, propertyValue);
476   }
477 }
478
479 Property::Value Object::GetProperty(Property::Index index) const
480 {
481   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
482
483   Property::Value value;
484
485   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
486   {
487     value = GetDefaultProperty( index );
488   }
489   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
490   {
491     const TypeInfo* typeInfo( GetTypeInfo() );
492     if ( typeInfo )
493     {
494       value = typeInfo->GetProperty( this, index );
495     }
496     else
497     {
498       DALI_LOG_ERROR("Cannot find property index\n");
499     }
500   }
501   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
502   {
503     // check whether the animatable property is registered already, if not then register one.
504     AnimatablePropertyMetadata* animatableProperty = RegisterAnimatableProperty( index );
505     if(!animatableProperty)
506     {
507       DALI_LOG_ERROR("Cannot find property index\n");
508     }
509     else
510     {
511       // get the animatable property value
512       value = GetPropertyValue( animatableProperty );
513     }
514   }
515   else if(mCustomProperties.Count() > 0)
516   {
517     CustomPropertyMetadata* custom = FindCustomProperty( index );
518     if(custom)
519     {
520       // get the custom property value
521       value = GetPropertyValue( custom );
522     }
523     else
524     {
525       DALI_LOG_ERROR("Invalid property index\n");
526     }
527   } // if custom
528
529   return value;
530 }
531
532 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
533 {
534   indices.Clear();
535
536   // Default Properties
537   GetDefaultPropertyIndices( indices );
538
539   // Manual Properties
540   const TypeInfo* typeInfo( GetTypeInfo() );
541   if ( typeInfo )
542   {
543     typeInfo->GetPropertyIndices( indices );
544   }
545
546   // Custom Properties
547   if ( mCustomProperties.Count() > 0 )
548   {
549     indices.Reserve( indices.Size() + mCustomProperties.Count() );
550
551     PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin();
552     const PropertyMetadataLookup::ConstIterator endIter = mCustomProperties.End();
553     int i=0;
554     for ( ; iter != endIter; ++iter, ++i )
555     {
556       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( *iter );
557       if ( custom->childPropertyIndex != Property::INVALID_INDEX )
558       {
559         // If it is a child property, add the child property index
560         indices.PushBack( custom->childPropertyIndex );
561       }
562       else
563       {
564         indices.PushBack( PROPERTY_CUSTOM_START_INDEX + i );
565       }
566     }
567   }
568 }
569
570 Property::Index Object::RegisterSceneGraphProperty(const std::string& name, Property::Index index, const Property::Value& propertyValue) const
571 {
572   // Create a new property
573   Dali::Internal::OwnerPointer<PropertyBase> newProperty;
574
575   switch ( propertyValue.GetType() )
576   {
577     case Property::BOOLEAN:
578     {
579       newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
580       break;
581     }
582
583     case Property::INTEGER:
584     {
585       newProperty = new AnimatableProperty<int>( propertyValue.Get<int>() );
586       break;
587     }
588
589     case Property::FLOAT:
590     {
591       newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
592       break;
593     }
594
595     case Property::VECTOR2:
596     {
597       newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
598       break;
599     }
600
601     case Property::VECTOR3:
602     {
603       newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
604       break;
605     }
606
607     case Property::VECTOR4:
608     {
609       newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
610       break;
611     }
612
613     case Property::MATRIX:
614     {
615       newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
616       break;
617     }
618
619     case Property::MATRIX3:
620     {
621       newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
622       break;
623     }
624
625     case Property::ROTATION:
626     {
627       newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
628       break;
629     }
630
631     case Property::RECTANGLE:
632     case Property::STRING:
633     case Property::ARRAY:
634     case Property::MAP:
635     case Property::NONE:
636     {
637       DALI_ASSERT_ALWAYS( !"PropertyType is not animatable" );
638       break;
639     }
640   }
641
642   // get the scene property owner from derived class
643   const SceneGraph::PropertyOwner* scenePropertyOwner = GetPropertyOwner();
644   // we can only pass properties to scene graph side if there is a scene object
645   if( scenePropertyOwner )
646   {
647     // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
648     const PropertyBase* property = newProperty.Get();
649     if(index >= PROPERTY_CUSTOM_START_INDEX)
650     {
651       DALI_ASSERT_ALWAYS( index <= PROPERTY_CUSTOM_MAX_INDEX && "Too many custom properties have been registered" );
652
653       mCustomProperties.PushBack( new CustomPropertyMetadata( name, propertyValue.GetType(), property ) );
654     }
655     else
656     {
657       mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, Property::INVALID_COMPONENT_INDEX, propertyValue.GetType(), property ) ); // base property
658     }
659
660     // queue a message to add the property
661     InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *scenePropertyOwner, newProperty.Release() ); // Message takes ownership
662
663     // notify the derived class (optional) method in case it needs to do some more work on the new property
664     // note! have to use the local pointer as OwnerPointer now points to NULL as it handed over its ownership
665     NotifyScenePropertyInstalled( *property, name, index );
666
667     return index;
668   }
669   else
670   {
671     // property was orphaned and killed so return invalid index
672     return Property::INVALID_INDEX;
673   }
674 }
675
676 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue )
677 {
678   return RegisterProperty( name, propertyValue, Property::ANIMATABLE );
679 }
680
681 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
682 {
683   // If property with the required name already exists, then just set it.
684   Property::Index index = GetPropertyIndex( name );
685   if( index != Property::INVALID_INDEX )
686   {
687     SetProperty( index, propertyValue );
688   }
689   else
690   {
691     // Otherwise register the property
692
693     if(Property::ANIMATABLE == accessMode)
694     {
695       index = RegisterSceneGraphProperty( name, PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count(), propertyValue );
696       AddUniformMapping( index, name );
697     }
698     else
699     {
700       // Add entry to the property lookup
701       index = PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count();
702
703       CustomPropertyMetadata* customProperty = new CustomPropertyMetadata( name, propertyValue, accessMode );
704
705       // Resolve index for the child property
706       Object* parent = GetParentObject();
707       if( parent )
708       {
709         const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
710         if( parentTypeInfo )
711         {
712           Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( name );
713           if( childPropertyIndex != Property::INVALID_INDEX )
714           {
715             customProperty->childPropertyIndex = childPropertyIndex;
716             index = childPropertyIndex;
717           }
718         }
719       }
720
721       mCustomProperties.PushBack( customProperty );
722     }
723   }
724
725   return index;
726 }
727
728 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index,
729                                                                 int componentIndex,
730                                                                 const Dali::PropertyCondition& condition)
731 {
732   if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
733   {
734     if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
735     {
736       DALI_ASSERT_ALWAYS( false && "Property notification added to event side only property." );
737     }
738     else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
739     {
740       // check whether the animatable property is registered already, if not then register one.
741       AnimatablePropertyMetadata* animatable = RegisterAnimatableProperty( index );
742       DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
743     }
744     else if ( mCustomProperties.Count() > 0 )
745     {
746       CustomPropertyMetadata* custom = FindCustomProperty( index );
747       DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
748       DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
749     }
750   }
751
752   Dali::Handle self(this);
753   Property target( self, index );
754
755   PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
756   Dali::PropertyNotification propertyNotification(internal.Get());
757
758   if( !mPropertyNotifications )
759   {
760     mPropertyNotifications = new PropertyNotificationContainer;
761   }
762   mPropertyNotifications->push_back(propertyNotification);
763
764   return propertyNotification;
765 }
766
767 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
768 {
769   if( mPropertyNotifications )
770   {
771     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
772     while(iter != mPropertyNotifications->end() )
773     {
774       if(*iter == propertyNotification)
775       {
776         mPropertyNotifications->erase(iter);
777         // As we can't ensure all references are removed, we can just disable
778         // the notification.
779         GetImplementation(propertyNotification).Disable();
780         return;
781       }
782       ++iter;
783     }
784   }
785 }
786
787 void Object::RemovePropertyNotifications()
788 {
789   if( mPropertyNotifications )
790   {
791     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
792     while(iter != mPropertyNotifications->end() )
793     {
794       // As we can't ensure all references are removed, we can just disable
795       // the notification.
796       GetImplementation(*iter).Disable();
797       ++iter;
798     }
799
800     mPropertyNotifications->clear();
801   }
802 }
803
804 void Object::EnablePropertyNotifications()
805 {
806   if( mPropertyNotifications )
807   {
808     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
809     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
810
811     for( ; iter != endIter; ++iter )
812     {
813       GetImplementation(*iter).Enable();
814     }
815   }
816 }
817
818 void Object::DisablePropertyNotifications()
819 {
820   if( mPropertyNotifications )
821   {
822     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
823     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
824
825     for( ; iter != endIter; ++iter )
826     {
827       GetImplementation(*iter).Disable();
828     }
829   }
830 }
831
832 void Object::AddUniformMapping( Property::Index propertyIndex, const std::string& uniformName ) const
833 {
834   // Get the address of the property if it's a scene property
835   const PropertyInputImpl* propertyPtr = GetSceneObjectInputProperty( propertyIndex );
836
837   // Check instead for newly registered properties
838   if( propertyPtr == NULL )
839   {
840     PropertyMetadata* animatable = FindAnimatableProperty( propertyIndex );
841     if( animatable != NULL )
842     {
843       propertyPtr = animatable->GetSceneGraphProperty();
844     }
845   }
846
847   if( propertyPtr == NULL )
848   {
849     PropertyMetadata* custom = FindCustomProperty( propertyIndex );
850     if( custom != NULL )
851     {
852       propertyPtr = custom->GetSceneGraphProperty();
853     }
854   }
855
856   if( propertyPtr != NULL )
857   {
858     const SceneGraph::PropertyOwner* sceneObject = GetPropertyOwner();
859
860     if( sceneObject != NULL )
861     {
862       SceneGraph::UniformPropertyMapping* map = new SceneGraph::UniformPropertyMapping( uniformName, propertyPtr );
863       // Message takes ownership of Uniform map (and will delete it after copy)
864       AddUniformMapMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *sceneObject, map);
865     }
866     else
867     {
868       DALI_ASSERT_ALWAYS(0 && "MESH_REWORK - Need to store property whilst off-stage" );
869     }
870   }
871 }
872
873 void Object::RemoveUniformMapping( const std::string& uniformName )
874 {
875   const SceneGraph::PropertyOwner* sceneObject = GetSceneObject();
876   RemoveUniformMapMessage( GetEventThreadServices(), *sceneObject, uniformName);
877 }
878
879 Property::Value Object::GetPropertyValue( const PropertyMetadata* entry ) const
880 {
881   Property::Value value;
882
883   DALI_ASSERT_ALWAYS( entry && "Invalid property metadata" );
884
885   if( !entry->IsAnimatable() )
886   {
887     value = entry->value;
888   }
889   else
890   {
891     BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
892
893     switch ( entry->GetType() )
894     {
895       case Property::BOOLEAN:
896       {
897         const AnimatableProperty<bool>* property = static_cast< const AnimatableProperty<bool>* >( entry->GetSceneGraphProperty() );
898         DALI_ASSERT_DEBUG( NULL != property );
899
900         value = (*property)[ bufferIndex ];
901         break;
902       }
903
904       case Property::INTEGER:
905       {
906         const AnimatableProperty<int>* property = static_cast< const AnimatableProperty<int>* >( entry->GetSceneGraphProperty() );
907         DALI_ASSERT_DEBUG( NULL != property );
908
909         value = (*property)[ bufferIndex ];
910         break;
911       }
912
913       case Property::FLOAT:
914       {
915         const AnimatableProperty<float>* property = static_cast< const AnimatableProperty<float>* >( entry->GetSceneGraphProperty() );
916         DALI_ASSERT_DEBUG( NULL != property );
917
918         value = (*property)[ bufferIndex ];
919         break;
920       }
921
922       case Property::VECTOR2:
923       {
924         const AnimatableProperty<Vector2>* property = static_cast< const AnimatableProperty<Vector2>* >( entry->GetSceneGraphProperty() );
925         DALI_ASSERT_DEBUG( NULL != property );
926
927         if(entry->componentIndex == 0)
928         {
929           value = (*property)[ bufferIndex ].x;
930         }
931         else if(entry->componentIndex == 1)
932         {
933           value = (*property)[ bufferIndex ].y;
934         }
935         else
936         {
937           value = (*property)[ bufferIndex ];
938         }
939         break;
940       }
941
942       case Property::VECTOR3:
943       {
944         const AnimatableProperty<Vector3>* property = static_cast< const AnimatableProperty<Vector3>* >( entry->GetSceneGraphProperty() );
945         DALI_ASSERT_DEBUG( NULL != property );
946
947         if(entry->componentIndex == 0)
948         {
949           value = (*property)[ bufferIndex ].x;
950         }
951         else if(entry->componentIndex == 1)
952         {
953           value = (*property)[ bufferIndex ].y;
954         }
955         else if(entry->componentIndex == 2)
956         {
957           value = (*property)[ bufferIndex ].z;
958         }
959         else
960         {
961           value = (*property)[ bufferIndex ];
962         }
963         break;
964       }
965
966       case Property::VECTOR4:
967       {
968         const AnimatableProperty<Vector4>* property = static_cast< const AnimatableProperty<Vector4>* >( entry->GetSceneGraphProperty() );
969         DALI_ASSERT_DEBUG( NULL != property );
970
971         if(entry->componentIndex == 0)
972         {
973           value = (*property)[ bufferIndex ].x;
974         }
975         else if(entry->componentIndex == 1)
976         {
977           value = (*property)[ bufferIndex ].y;
978         }
979         else if(entry->componentIndex == 2)
980         {
981           value = (*property)[ bufferIndex ].z;
982         }
983         else if(entry->componentIndex == 3)
984         {
985           value = (*property)[ bufferIndex ].w;
986         }
987         else
988         {
989           value = (*property)[ bufferIndex ];
990         }
991         break;
992       }
993
994       case Property::MATRIX:
995       {
996         const AnimatableProperty<Matrix>* property = static_cast< const AnimatableProperty<Matrix>* >( entry->GetSceneGraphProperty() );
997         DALI_ASSERT_DEBUG( NULL != property );
998
999         value = (*property)[ bufferIndex ];
1000         break;
1001       }
1002
1003       case Property::MATRIX3:
1004       {
1005         const AnimatableProperty<Matrix3>* property = static_cast< const AnimatableProperty<Matrix3>* >( entry->GetSceneGraphProperty() );
1006         DALI_ASSERT_DEBUG( NULL != property );
1007
1008         value = (*property)[ bufferIndex ];
1009         break;
1010       }
1011
1012       case Property::ROTATION:
1013       {
1014         const AnimatableProperty<Quaternion>* property = static_cast< const AnimatableProperty<Quaternion>* >( entry->GetSceneGraphProperty() );
1015         DALI_ASSERT_DEBUG( NULL != property );
1016
1017         value = (*property)[ bufferIndex ];
1018         break;
1019       }
1020
1021       default:
1022       {
1023         DALI_ASSERT_ALWAYS( false && "PropertyType enumeration is out of bounds" );
1024         break;
1025       }
1026     } // switch(type)
1027   } // if animatable
1028
1029   return value;
1030 }
1031
1032 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
1033 {
1034   switch ( entry.GetType() )
1035   {
1036     case Property::BOOLEAN:
1037     {
1038       const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
1039       DALI_ASSERT_DEBUG( NULL != property );
1040
1041       // property is being used in a separate thread; queue a message to set the property
1042       BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
1043       break;
1044     }
1045
1046     case Property::INTEGER:
1047     {
1048       const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
1049       DALI_ASSERT_DEBUG( NULL != property );
1050
1051       // property is being used in a separate thread; queue a message to set the property
1052       BakeMessage<int>( GetEventThreadServices(), *property, value.Get<int>() );
1053       break;
1054     }
1055
1056     case Property::FLOAT:
1057     {
1058       const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
1059       DALI_ASSERT_DEBUG( NULL != property );
1060
1061       // property is being used in a separate thread; queue a message to set the property
1062       BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
1063       break;
1064     }
1065
1066     case Property::VECTOR2:
1067     {
1068       const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
1069       DALI_ASSERT_DEBUG( NULL != property );
1070
1071       // property is being used in a separate thread; queue a message to set the property
1072       if(entry.componentIndex == 0)
1073       {
1074         SetXComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1075       }
1076       else if(entry.componentIndex == 1)
1077       {
1078         SetYComponentMessage<Vector2>( GetEventThreadServices(), *property, value.Get<float>() );
1079       }
1080       else
1081       {
1082         BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
1083       }
1084       break;
1085     }
1086
1087     case Property::VECTOR3:
1088     {
1089       const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
1090       DALI_ASSERT_DEBUG( NULL != property );
1091
1092       // property is being used in a separate thread; queue a message to set the property
1093       if(entry.componentIndex == 0)
1094       {
1095         SetXComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1096       }
1097       else if(entry.componentIndex == 1)
1098       {
1099         SetYComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1100       }
1101       else if(entry.componentIndex == 2)
1102       {
1103         SetZComponentMessage<Vector3>( GetEventThreadServices(), *property, value.Get<float>() );
1104       }
1105       else
1106       {
1107         BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
1108       }
1109
1110       break;
1111     }
1112
1113     case Property::VECTOR4:
1114     {
1115       const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
1116       DALI_ASSERT_DEBUG( NULL != property );
1117
1118       // property is being used in a separate thread; queue a message to set the property
1119       if(entry.componentIndex == 0)
1120       {
1121         SetXComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1122       }
1123       else if(entry.componentIndex == 1)
1124       {
1125         SetYComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1126       }
1127       else if(entry.componentIndex == 2)
1128       {
1129         SetZComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1130       }
1131       else if(entry.componentIndex == 3)
1132       {
1133         SetWComponentMessage<Vector4>( GetEventThreadServices(), *property, value.Get<float>() );
1134       }
1135       else
1136       {
1137         BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
1138       }
1139       break;
1140     }
1141
1142     case Property::ROTATION:
1143     {
1144       const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1145       DALI_ASSERT_DEBUG( NULL != property );
1146
1147       // property is being used in a separate thread; queue a message to set the property
1148       BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1149       break;
1150     }
1151
1152     case Property::MATRIX:
1153     {
1154       const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1155       DALI_ASSERT_DEBUG( NULL != property );
1156
1157       // property is being used in a separate thread; queue a message to set the property
1158       BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1159       break;
1160     }
1161
1162     case Property::MATRIX3:
1163     {
1164       const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1165       DALI_ASSERT_DEBUG( NULL != property );
1166
1167       // property is being used in a separate thread; queue a message to set the property
1168       BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1169       break;
1170     }
1171
1172     default:
1173     {
1174       // non-animatable scene graph property, do nothing
1175     }
1176   }
1177 }
1178
1179 const TypeInfo* Object::GetTypeInfo() const
1180 {
1181   if ( !mTypeInfo )
1182   {
1183     // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1184     // especially as the type-info does not change during the life-time of an application
1185
1186     Dali::TypeInfo typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1187     if ( typeInfoHandle )
1188     {
1189       mTypeInfo = &GetImplementation( typeInfoHandle );
1190     }
1191   }
1192
1193   return mTypeInfo;
1194 }
1195
1196 void Object::ApplyConstraint( ConstraintBase& constraint )
1197 {
1198   if( !mConstraints )
1199   {
1200     mConstraints = new ConstraintContainer;
1201   }
1202   mConstraints->push_back( Dali::Constraint( &constraint ) );
1203 }
1204
1205 void Object::RemoveConstraint( ConstraintBase& constraint )
1206 {
1207   // NULL if the Constraint sources are destroyed before Constraint::Apply()
1208   if( mConstraints )
1209   {
1210     ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
1211     if( it != mConstraints->end() )
1212     {
1213       mConstraints->erase( it );
1214     }
1215   }
1216 }
1217
1218 void Object::RemoveConstraints()
1219 {
1220   // guard against constraint sending messages during core destruction
1221   if( mConstraints && Stage::IsInstalled() )
1222   {
1223     // If we have nothing in the scene-graph, just clear constraint containers
1224     const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
1225     if ( NULL != propertyOwner )
1226     {
1227       const ConstraintConstIter endIter = mConstraints->end();
1228       for ( ConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
1229       {
1230         GetImplementation( *iter ).RemoveInternal();
1231       }
1232     }
1233
1234     delete mConstraints;
1235     mConstraints = NULL;
1236   }
1237 }
1238
1239 void Object::RemoveConstraints( unsigned int tag )
1240 {
1241   // guard against constraint sending messages during core destruction
1242   if( mConstraints && Stage::IsInstalled() )
1243   {
1244     ConstraintIter iter( mConstraints->begin() );
1245     while(iter != mConstraints->end() )
1246     {
1247       ConstraintBase& constraint = GetImplementation( *iter );
1248       if( constraint.GetTag() == tag )
1249       {
1250         GetImplementation( *iter ).RemoveInternal();
1251         iter = mConstraints->erase( iter );
1252       }
1253       else
1254       {
1255         ++iter;
1256       }
1257     }
1258
1259     if ( mConstraints->empty() )
1260     {
1261       delete mConstraints;
1262       mConstraints = NULL;
1263     }
1264   }
1265 }
1266
1267 void Object::SetTypeInfo( const TypeInfo* typeInfo )
1268 {
1269   mTypeInfo = typeInfo;
1270 }
1271
1272 Object::~Object()
1273 {
1274   // Notification for observers
1275   for( ConstObserverIter iter = mObservers.Begin(), endIter =  mObservers.End(); iter != endIter; ++iter)
1276   {
1277     (*iter)->ObjectDestroyed(*this);
1278   }
1279
1280   delete mConstraints;
1281   delete mPropertyNotifications;
1282 }
1283
1284 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1285 {
1286   CustomPropertyMetadata* property( NULL );
1287   if ( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX ) )
1288   {
1289     for ( std::size_t arrayIndex = 0; arrayIndex < mCustomProperties.Count(); arrayIndex++ )
1290     {
1291       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1292       if( custom->childPropertyIndex == index )
1293       {
1294         property = custom;
1295       }
1296     }
1297   }
1298   else
1299   {
1300     int arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1301     if( arrayIndex >= 0 )
1302     {
1303       if( arrayIndex < (int)mCustomProperties.Count() ) // we can only access the first 2 billion custom properties
1304       {
1305         property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1306       }
1307     }
1308   }
1309   return property;
1310 }
1311
1312 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1313 {
1314   for ( int arrayIndex = 0; arrayIndex < (int)mAnimatableProperties.Count(); arrayIndex++ )
1315   {
1316     AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( mAnimatableProperties[ arrayIndex ] );
1317     if( property->index == index )
1318     {
1319       return property;
1320     }
1321   }
1322   return NULL;
1323 }
1324
1325 AnimatablePropertyMetadata* Object::RegisterAnimatableProperty(Property::Index index) const
1326 {
1327   DALI_ASSERT_ALWAYS( (( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ))
1328                       && "Property index is out of bounds" );
1329
1330   // check whether the animatable property is registered already, if not then register one.
1331   AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
1332   if(!animatableProperty)
1333   {
1334     const TypeInfo* typeInfo( GetTypeInfo() );
1335     if (typeInfo)
1336     {
1337       Property::Index basePropertyIndex = typeInfo->GetBasePropertyIndex(index);
1338       if(basePropertyIndex == Property::INVALID_INDEX)
1339       {
1340         // If the property is not a component of a base property, register the whole property itself.
1341         const  std::string& propertyName = typeInfo->GetPropertyName(index);
1342         RegisterSceneGraphProperty(propertyName, index, typeInfo->GetPropertyDefaultValue(index));
1343         AddUniformMapping( index, propertyName );
1344       }
1345       else
1346       {
1347         // Since the property is a component of a base property, check whether the base property is regsitered.
1348         animatableProperty = FindAnimatableProperty( basePropertyIndex );
1349         if(!animatableProperty)
1350         {
1351           // If the base property is not registered yet, register the base property first.
1352           const  std::string& basePropertyName = typeInfo->GetPropertyName(basePropertyIndex);
1353           if(Property::INVALID_INDEX != RegisterSceneGraphProperty(basePropertyName, basePropertyIndex, Property::Value(typeInfo->GetPropertyType(basePropertyIndex))))
1354           {
1355             animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1356             AddUniformMapping( basePropertyIndex, basePropertyName );
1357           }
1358         }
1359
1360         if(animatableProperty)
1361         {
1362           // Create the metadata for the property component.
1363           mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, typeInfo->GetComponentIndex(index), animatableProperty->GetType(), animatableProperty->GetSceneGraphProperty() ) );
1364         }
1365       }
1366
1367       // The metadata has just been added and therefore should be in the end of the vector.
1368       animatableProperty = static_cast<AnimatablePropertyMetadata*>(mAnimatableProperties[mAnimatableProperties.Size()-1]);
1369     }
1370   }
1371
1372   return animatableProperty;
1373 }
1374
1375 void Object::ResolveChildProperties()
1376 {
1377   // Resolve index for the child property
1378   Object* parent = GetParentObject();
1379   if( parent )
1380   {
1381     const TypeInfo* parentTypeInfo( parent->GetTypeInfo() );
1382     if( parentTypeInfo )
1383     {
1384       // Go through each custom property
1385       for ( int arrayIndex = 0; arrayIndex < (int)mCustomProperties.Count(); arrayIndex++ )
1386       {
1387         CustomPropertyMetadata* customProperty = static_cast<CustomPropertyMetadata*>( mCustomProperties[ arrayIndex ] );
1388
1389         if( customProperty->name == "" )
1390         {
1391           if( customProperty->childPropertyIndex != Property::INVALID_INDEX )
1392           {
1393             // Resolve name for any child property with no name
1394             customProperty->name = parentTypeInfo->GetChildPropertyName( customProperty->childPropertyIndex );
1395           }
1396         }
1397         else
1398         {
1399           Property::Index childPropertyIndex = parentTypeInfo->GetChildPropertyIndex( customProperty->name );
1400           if( childPropertyIndex != Property::INVALID_INDEX )
1401           {
1402             // Resolve index for any property with a name that matches the parent's child property name
1403             customProperty->childPropertyIndex = childPropertyIndex;
1404           }
1405         }
1406       }
1407     }
1408   }
1409 }
1410
1411 } // namespace Internal
1412
1413 } // namespace Dali