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