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