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