Lazy register animatable property if not registered yet
[platform/core/uifw/dali-core.git] / dali / internal / event / common / object-impl.cpp
1 /*
2  * Copyright (c) 2014 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/event/animation/active-constraint-base.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 } // unnamed namespace
54
55 Object::Object()
56 : mEventThreadServices( *Stage::GetCurrent() ),
57   mTypeInfo( NULL ),
58   mConstraints( NULL ),
59   mPropertyNotifications( NULL )
60 {
61 }
62
63 void Object::AddObserver(Observer& observer)
64 {
65   // make sure an observer doesn't observe the same object twice
66   // otherwise it will get multiple calls to OnSceneObjectAdd(), OnSceneObjectRemove() and ObjectDestroyed()
67   DALI_ASSERT_DEBUG( mObservers.End() == std::find( mObservers.Begin(), mObservers.End(), &observer));
68
69   mObservers.PushBack( &observer );
70 }
71
72 void Object::RemoveObserver(Observer& observer)
73 {
74   // Find the observer...
75   const ConstObserverIter endIter =  mObservers.End();
76   for( ObserverIter iter = mObservers.Begin(); iter != endIter; ++iter)
77   {
78     if( (*iter) == &observer)
79     {
80       mObservers.Erase( iter );
81       break;
82     }
83   }
84   DALI_ASSERT_DEBUG(endIter != mObservers.End());
85 }
86
87 void Object::OnSceneObjectAdd()
88 {
89   // Notification for this object's constraints
90   if( mConstraints )
91   {
92     const ActiveConstraintConstIter endIter = mConstraints->end();
93     for ( ActiveConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
94     {
95       ActiveConstraintBase& baseConstraint = GetImplementation( *iter );
96       baseConstraint.OnParentSceneObjectAdded();
97     }
98   }
99
100   // Notification for observers
101   for( ConstObserverIter iter = mObservers.Begin(),  endIter =  mObservers.End(); iter != endIter; ++iter)
102   {
103     (*iter)->SceneObjectAdded(*this);
104   }
105
106   // enable property notifications in scene graph
107   EnablePropertyNotifications();
108 }
109
110 void Object::OnSceneObjectRemove()
111 {
112   // Notification for this object's constraints
113   if( mConstraints )
114   {
115     const ActiveConstraintConstIter endIter = mConstraints->end();
116     for ( ActiveConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
117     {
118       ActiveConstraintBase& baseConstraint = GetImplementation( *iter );
119       baseConstraint.OnParentSceneObjectRemoved();
120     }
121   }
122
123   // Notification for observers
124   for( ConstObserverIter iter = mObservers.Begin(), endIter = mObservers.End(); iter != endIter; ++iter )
125   {
126     (*iter)->SceneObjectRemoved(*this);
127   }
128
129   // disable property notifications in scene graph
130   DisablePropertyNotifications();
131 }
132
133 int Object::GetPropertyComponentIndex( Property::Index index ) const
134 {
135   return Property::INVALID_COMPONENT_INDEX;
136 }
137
138 bool Object::Supports( Capability capability ) const
139 {
140   return (capability & SUPPORTED_CAPABILITIES);
141 }
142
143 unsigned int Object::GetPropertyCount() const
144 {
145   unsigned int count = GetDefaultPropertyCount();
146
147   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Default Properties: %d\n", count );
148
149   const TypeInfo* typeInfo( GetTypeInfo() );
150   if ( typeInfo )
151   {
152     unsigned int manual( typeInfo->GetPropertyCount() );
153     count += manual;
154
155     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Manual Properties:  %d\n", manual );
156   }
157
158   unsigned int custom( mCustomProperties.Count() );
159   count += custom;
160   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Custom Properties:  %d\n", custom );
161
162   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Total Properties:   %d\n", count );
163
164   return count;
165 }
166
167 std::string Object::GetPropertyName( Property::Index index ) const
168 {
169   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index out of bounds" );
170
171   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
172   {
173     return GetDefaultPropertyName( index );
174   }
175
176   if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
177     || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
178   {
179     const TypeInfo* typeInfo( GetTypeInfo() );
180     if ( typeInfo )
181     {
182       return typeInfo->GetPropertyName( index );
183     }
184     else
185     {
186       DALI_ASSERT_ALWAYS( ! "Property index is invalid" );
187     }
188   }
189
190   CustomPropertyMetadata* custom = FindCustomProperty( index );
191   if( custom )
192   {
193     return custom->name;
194   }
195   return "";
196 }
197
198 Property::Index Object::GetPropertyIndex(const std::string& name) const
199 {
200   Property::Index index = GetDefaultPropertyIndex( name );
201
202   if(index == Property::INVALID_INDEX)
203   {
204     const TypeInfo* typeInfo( GetTypeInfo() );
205     if ( typeInfo )
206     {
207       index = typeInfo->GetPropertyIndex( name );
208       if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
209       {
210         // check whether the animatable property is registered already, if not then register one.
211         AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
212         if(!animatableProperty)
213         {
214           const TypeInfo* typeInfo( GetTypeInfo() );
215           if (typeInfo)
216           {
217             index = RegisterSceneGraphProperty(typeInfo->GetPropertyName(index), index, Property::Value(typeInfo->GetPropertyType(index)));
218           }
219         }
220       }
221     }
222   }
223
224   if( (index == Property::INVALID_INDEX)&&( mCustomProperties.Count() > 0 ) )
225   {
226     Property::Index count = PROPERTY_CUSTOM_START_INDEX;
227     const PropertyMetadataLookup::ConstIterator end = mCustomProperties.End();
228     for( PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin(); iter != end; ++iter, ++count )
229     {
230       CustomPropertyMetadata* custom = static_cast<CustomPropertyMetadata*>(*iter);
231       if ( custom->name == name )
232       {
233         index = count;
234         break;
235       }
236     }
237   }
238
239   return index;
240 }
241
242 bool Object::IsPropertyWritable( Property::Index index ) const
243 {
244   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
245
246   bool writable = false;
247
248   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
249   {
250     writable = IsDefaultPropertyWritable( index );
251   }
252   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
253   {
254     const TypeInfo* typeInfo( GetTypeInfo() );
255     if ( typeInfo )
256     {
257       writable = typeInfo->IsPropertyWritable( index );
258     }
259     else
260     {
261       DALI_ASSERT_ALWAYS( ! "Invalid property index" );
262     }
263   }
264   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
265   {
266     // Type Registry scene-graph properties are writable.
267     writable = true;
268   }
269   else
270   {
271     CustomPropertyMetadata* custom = FindCustomProperty( index );
272     if( custom )
273     {
274       writable = custom->IsWritable();
275     }
276   }
277
278   return writable;
279 }
280
281 bool Object::IsPropertyAnimatable( Property::Index index ) const
282 {
283   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
284
285   bool animatable = false;
286
287   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
288   {
289     animatable = IsDefaultPropertyAnimatable( index );
290   }
291   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
292   {
293     // Type Registry event-thread only properties are not animatable.
294     animatable = false;
295   }
296   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
297   {
298     // Type Registry scene-graph properties are animatable.
299     animatable = true;
300   }
301   else
302   {
303     CustomPropertyMetadata* custom = FindCustomProperty( index );
304     if( custom )
305     {
306       animatable = custom->IsAnimatable();
307     }
308   }
309
310   return animatable;
311 }
312
313 bool Object::IsPropertyAConstraintInput( Property::Index index ) const
314 {
315   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds");
316
317   bool isConstraintInput = false;
318
319   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
320   {
321     isConstraintInput = IsDefaultPropertyAConstraintInput( index );
322   }
323   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
324   {
325     // Type Registry event-thread only properties cannot be used as an input to a constraint.
326     isConstraintInput = false;
327   }
328   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
329   {
330     // scene graph properties can be used as input to a constraint.
331     isConstraintInput = true;
332   }
333   else
334   {
335     CustomPropertyMetadata* custom = FindCustomProperty( index );
336     if( custom )
337     {
338       // ... custom properties can be used as input to a constraint.
339       isConstraintInput = true;
340     }
341   }
342
343   return isConstraintInput;
344 }
345
346 Property::Type Object::GetPropertyType( Property::Index index ) const
347 {
348   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
349
350   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
351   {
352     return GetDefaultPropertyType( index );
353   }
354
355   if ( ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
356     || ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) ) )
357   {
358     const TypeInfo* typeInfo( GetTypeInfo() );
359     if ( typeInfo )
360     {
361       return typeInfo->GetPropertyType( index );
362     }
363     else
364     {
365       DALI_ASSERT_ALWAYS( ! "Cannot find property index" );
366     }
367   }
368
369   CustomPropertyMetadata* custom = FindCustomProperty( index );
370   if( custom )
371   {
372     return custom->type;
373   }
374   return Property::NONE;
375 }
376
377 void Object::SetProperty( Property::Index index, const Property::Value& propertyValue )
378 {
379   DALI_ASSERT_ALWAYS(index > Property::INVALID_INDEX && "Property index is out of bounds" );
380
381   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
382   {
383     SetDefaultProperty( index, propertyValue );
384   }
385   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
386   {
387     const TypeInfo* typeInfo( GetTypeInfo() );
388     if ( typeInfo )
389     {
390       typeInfo->SetProperty( this, index, propertyValue );
391     }
392     else
393     {
394       DALI_LOG_ERROR("Cannot find property index\n");
395     }
396   }
397   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
398   {
399     // check whether the animatable property is registered already, if not then register one.
400     AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
401     if(!animatableProperty)
402     {
403       const TypeInfo* typeInfo( GetTypeInfo() );
404       if (!typeInfo)
405       {
406         DALI_LOG_ERROR("Cannot find property index\n");
407       }
408       else if ( Property::INVALID_INDEX == RegisterSceneGraphProperty( typeInfo->GetPropertyName( index ), index, propertyValue ) )
409       {
410         DALI_LOG_ERROR("Cannot register property\n");
411       }
412     }
413     else
414     {
415       // set the scene graph property value
416       SetSceneGraphProperty( index, *animatableProperty, propertyValue );
417     }
418   }
419   else
420   {
421     CustomPropertyMetadata* custom = FindCustomProperty( index );
422     if( custom )
423     {
424       if( custom->IsAnimatable() )
425       {
426         // set the scene graph property value
427         SetSceneGraphProperty( index, *custom, propertyValue );
428       }
429       else if( custom->IsWritable() )
430       {
431         custom->value = propertyValue;
432         OnPropertySet(index, propertyValue);
433       }
434       // trying to set value on read only property is no-op
435     }
436     else
437     {
438       DALI_LOG_ERROR("Invalid property index\n");
439     }
440   }
441 }
442
443 Property::Value Object::GetProperty(Property::Index index) const
444 {
445   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
446
447   Property::Value value;
448
449   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
450   {
451     value = GetDefaultProperty( index );
452   }
453   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
454   {
455     const TypeInfo* typeInfo( GetTypeInfo() );
456     if ( typeInfo )
457     {
458       value = typeInfo->GetProperty( this, index );
459     }
460     else
461     {
462       DALI_LOG_ERROR("Cannot find property index\n");
463     }
464   }
465   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
466   {
467     // check whether the animatable property is registered already, if not then register one.
468     AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
469     if(!animatableProperty)
470     {
471       const TypeInfo* typeInfo( GetTypeInfo() );
472       if (typeInfo)
473       {
474         if(Property::INVALID_INDEX != RegisterSceneGraphProperty(typeInfo->GetPropertyName(index), index, Property::Value(typeInfo->GetPropertyType(index))))
475         {
476           value = Property::Value(typeInfo->GetPropertyType(index)); // Return an initialized property value according to the type
477         }
478         else
479         {
480           DALI_LOG_ERROR("Cannot register property\n");
481         }
482       }
483       else
484       {
485         DALI_LOG_ERROR("Cannot find property index\n");
486       }
487     }
488     else
489     {
490       // get the animatable property value
491       value = GetPropertyValue( animatableProperty );
492     }
493   }
494   else if(mCustomProperties.Count() > 0)
495   {
496     CustomPropertyMetadata* custom = FindCustomProperty( index );
497     if(custom)
498     {
499       // get the custom property value
500       value = GetPropertyValue( custom );
501     }
502     else
503     {
504       DALI_LOG_ERROR("Invalid property index\n");
505     }
506   } // if custom
507
508   return value;
509 }
510
511 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
512 {
513   indices.clear();
514
515   // Default Properties
516   GetDefaultPropertyIndices( indices );
517
518   // Manual Properties
519   const TypeInfo* typeInfo( GetTypeInfo() );
520   if ( typeInfo )
521   {
522     typeInfo->GetPropertyIndices( indices );
523   }
524
525   // Custom Properties
526   if ( mCustomProperties.Count() > 0 )
527   {
528     indices.reserve( indices.size() + mCustomProperties.Count() );
529
530     PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin();
531     const PropertyMetadataLookup::ConstIterator endIter = mCustomProperties.End();
532     int i=0;
533     for ( ; iter != endIter; ++iter, ++i )
534     {
535       indices.push_back( PROPERTY_CUSTOM_START_INDEX + i );
536     }
537   }
538 }
539
540 Property::Index Object::RegisterSceneGraphProperty(const std::string& name, Property::Index index, const Property::Value& propertyValue) const
541 {
542   // Create a new property
543   Dali::Internal::OwnerPointer<PropertyBase> newProperty;
544
545   switch ( propertyValue.GetType() )
546   {
547     case Property::BOOLEAN:
548     {
549       newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
550       break;
551     }
552
553     case Property::FLOAT:
554     {
555       newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
556       break;
557     }
558
559     case Property::INTEGER:
560     {
561       newProperty = new AnimatableProperty<int>( propertyValue.Get<int>() );
562       break;
563     }
564
565     case Property::VECTOR2:
566     {
567       newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
568       break;
569     }
570
571     case Property::VECTOR3:
572     {
573       newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
574       break;
575     }
576
577     case Property::VECTOR4:
578     {
579       newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
580       break;
581     }
582
583     case Property::MATRIX:
584     {
585       newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
586       break;
587     }
588
589     case Property::MATRIX3:
590     {
591       newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
592       break;
593     }
594
595     case Property::ROTATION:
596     {
597       newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
598       break;
599     }
600
601     case Property::UNSIGNED_INTEGER:
602     case Property::RECTANGLE:
603     case Property::STRING:
604     case Property::ARRAY:
605     case Property::MAP:
606     {
607       DALI_LOG_WARNING( "Property Type %d\n", propertyValue.GetType() );
608       DALI_ASSERT_ALWAYS( !"PropertyType is not animatable" );
609       break;
610     }
611
612     default:
613     {
614       DALI_LOG_WARNING( "Property Type %d\n", propertyValue.GetType() );
615       DALI_ASSERT_ALWAYS( !"PropertyType enumeration is out of bounds" );
616       break;
617     }
618   }
619
620   // get the scene property owner from derived class
621   const SceneGraph::PropertyOwner* scenePropertyOwner = GetPropertyOwner();
622   // we can only pass properties to scene graph side if there is a scene object
623   if( scenePropertyOwner )
624   {
625     // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
626     const PropertyBase* property = newProperty.Get();
627     if(index >= PROPERTY_CUSTOM_START_INDEX)
628     {
629       mCustomProperties.PushBack( new CustomPropertyMetadata( name, propertyValue.GetType(), property ) );
630     }
631     else
632     {
633       mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, propertyValue.GetType(), property ) );
634     }
635
636     // queue a message to add the property
637     InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *scenePropertyOwner, newProperty.Release() ); // Message takes ownership
638
639     // notify the derived class (optional) method in case it needs to do some more work on the new property
640     // note! have to use the local pointer as OwnerPointer now points to NULL as it handed over its ownership
641     NotifyScenePropertyInstalled( *property, name, index );
642
643     return index;
644   }
645   else
646   {
647     // property was orphaned and killed so return invalid index
648     return Property::INVALID_INDEX;
649   }
650 }
651
652 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue)
653 {
654   return RegisterSceneGraphProperty(name, PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count(), propertyValue);
655 }
656
657 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode)
658 {
659   Property::Index index = Property::INVALID_INDEX;
660
661   if(Property::ANIMATABLE == accessMode)
662   {
663     index = RegisterProperty(name, propertyValue);
664   }
665   else
666   {
667     // Add entry to the property lookup
668     index = PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count();
669     mCustomProperties.PushBack( new CustomPropertyMetadata( name, propertyValue, accessMode ) );
670   }
671
672   return index;
673 }
674
675 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index,
676                                                                 int componentIndex,
677                                                                 const Dali::PropertyCondition& condition)
678 {
679   if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
680   {
681     if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
682     {
683       DALI_ASSERT_ALWAYS( false && "Property notification added to event side only property." );
684     }
685     else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
686     {
687       // check whether the animatable property is registered already, if not then register one.
688       AnimatablePropertyMetadata* animatable = FindAnimatableProperty( index );
689       if( !animatable )
690       {
691         const TypeInfo* typeInfo( GetTypeInfo() );
692         if ( typeInfo )
693         {
694           if( Property::INVALID_INDEX != RegisterSceneGraphProperty( typeInfo->GetPropertyName( index ), index, Property::Value( typeInfo->GetPropertyType( index ) ) ) )
695           {
696             animatable = FindAnimatableProperty( index );
697           }
698         }
699       }
700       DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
701     }
702     else if ( mCustomProperties.Count() > 0 )
703     {
704       CustomPropertyMetadata* custom = FindCustomProperty( index );
705       DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
706       DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
707     }
708   }
709
710   Dali::Handle self(this);
711   Property target( self, index );
712
713   PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
714   Dali::PropertyNotification propertyNotification(internal.Get());
715
716   if( !mPropertyNotifications )
717   {
718     mPropertyNotifications = new PropertyNotificationContainer;
719   }
720   mPropertyNotifications->push_back(propertyNotification);
721
722   return propertyNotification;
723 }
724
725 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
726 {
727   if( mPropertyNotifications )
728   {
729     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
730     while(iter != mPropertyNotifications->end() )
731     {
732       if(*iter == propertyNotification)
733       {
734         mPropertyNotifications->erase(iter);
735         // As we can't ensure all references are removed, we can just disable
736         // the notification.
737         GetImplementation(propertyNotification).Disable();
738         return;
739       }
740       ++iter;
741     }
742   }
743 }
744
745 void Object::RemovePropertyNotifications()
746 {
747   if( mPropertyNotifications )
748   {
749     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
750     while(iter != mPropertyNotifications->end() )
751     {
752       // As we can't ensure all references are removed, we can just disable
753       // the notification.
754       GetImplementation(*iter).Disable();
755       ++iter;
756     }
757
758     mPropertyNotifications->clear();
759   }
760 }
761
762 void Object::EnablePropertyNotifications()
763 {
764   if( mPropertyNotifications )
765   {
766     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
767     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
768
769     for( ; iter != endIter; ++iter )
770     {
771       GetImplementation(*iter).Enable();
772     }
773   }
774 }
775
776 void Object::DisablePropertyNotifications()
777 {
778   if( mPropertyNotifications )
779   {
780     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
781     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
782
783     for( ; iter != endIter; ++iter )
784     {
785       GetImplementation(*iter).Disable();
786     }
787   }
788 }
789
790 Dali::ActiveConstraint Object::ApplyConstraint( Constraint& constraint )
791 {
792   return Dali::ActiveConstraint( DoApplyConstraint( constraint, Dali::Handle() ) );
793 }
794
795 Dali::ActiveConstraint Object::ApplyConstraint( Constraint& constraint, Dali::Handle weightObject )
796 {
797   return Dali::ActiveConstraint( DoApplyConstraint( constraint, weightObject ) );
798 }
799
800 ActiveConstraintBase* Object::DoApplyConstraint( Constraint& constraint, Dali::Handle weightObject )
801 {
802   ActiveConstraintBase* activeConstraintImpl = constraint.CreateActiveConstraint();
803   DALI_ASSERT_DEBUG( NULL != activeConstraintImpl );
804
805   Dali::ActiveConstraint activeConstraint( activeConstraintImpl );
806
807   if( weightObject )
808   {
809     Object& weightObjectImpl = GetImplementation( weightObject );
810     Property::Index weightIndex = weightObjectImpl.GetPropertyIndex( "weight" );
811
812     if( Property::INVALID_INDEX != weightIndex )
813     {
814       activeConstraintImpl->SetCustomWeightObject( weightObjectImpl, weightIndex );
815     }
816   }
817
818   if( !mConstraints )
819   {
820     mConstraints = new ActiveConstraintContainer;
821   }
822   mConstraints->push_back( activeConstraint );
823
824   activeConstraintImpl->FirstApply( *this, constraint.GetApplyTime() );
825
826   return activeConstraintImpl;
827 }
828
829 Property::Value Object::GetPropertyValue( const PropertyMetadata* entry ) const
830 {
831   Property::Value value;
832
833   DALI_ASSERT_ALWAYS( entry && "Invalid property metadata" );
834
835   if( !entry->IsAnimatable() )
836   {
837     value = entry->value;
838   }
839   else
840   {
841     BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
842
843     switch ( entry->type )
844     {
845       case Property::BOOLEAN:
846       {
847         const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry->GetSceneGraphProperty() );
848         DALI_ASSERT_DEBUG( NULL != property );
849
850         value = (*property)[ bufferIndex ];
851         break;
852       }
853
854       case Property::FLOAT:
855       {
856         const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry->GetSceneGraphProperty() );
857         DALI_ASSERT_DEBUG( NULL != property );
858
859         value = (*property)[ bufferIndex ];
860         break;
861       }
862
863       case Property::INTEGER:
864       {
865         const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry->GetSceneGraphProperty() );
866         DALI_ASSERT_DEBUG( NULL != property );
867
868         value = (*property)[ bufferIndex ];
869         break;
870       }
871
872       case Property::VECTOR2:
873       {
874         const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry->GetSceneGraphProperty() );
875         DALI_ASSERT_DEBUG( NULL != property );
876
877         value = (*property)[ bufferIndex ];
878         break;
879       }
880
881       case Property::VECTOR3:
882       {
883         const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry->GetSceneGraphProperty() );
884         DALI_ASSERT_DEBUG( NULL != property );
885
886         value = (*property)[ bufferIndex ];
887         break;
888       }
889
890       case Property::VECTOR4:
891       {
892         const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry->GetSceneGraphProperty() );
893         DALI_ASSERT_DEBUG( NULL != property );
894
895         value = (*property)[ bufferIndex ];
896         break;
897       }
898
899       case Property::MATRIX:
900       {
901         const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry->GetSceneGraphProperty() );
902         DALI_ASSERT_DEBUG( NULL != property );
903
904         value = (*property)[ bufferIndex ];
905         break;
906       }
907
908       case Property::MATRIX3:
909       {
910         const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry->GetSceneGraphProperty() );
911         DALI_ASSERT_DEBUG( NULL != property );
912
913         value = (*property)[ bufferIndex ];
914         break;
915       }
916
917       case Property::ROTATION:
918       {
919         const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry->GetSceneGraphProperty() );
920         DALI_ASSERT_DEBUG( NULL != property );
921
922         value = (*property)[ bufferIndex ];
923         break;
924       }
925
926       default:
927       {
928         DALI_ASSERT_ALWAYS( false && "PropertyType enumeration is out of bounds" );
929         break;
930       }
931     } // switch(type)
932   } // if animatable
933
934   return value;
935 }
936
937 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
938 {
939   switch ( entry.type )
940   {
941     case Property::BOOLEAN:
942     {
943       const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
944       DALI_ASSERT_DEBUG( NULL != property );
945
946       // property is being used in a separate thread; queue a message to set the property
947       BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
948       break;
949     }
950
951     case Property::FLOAT:
952     {
953       const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
954       DALI_ASSERT_DEBUG( NULL != property );
955
956       // property is being used in a separate thread; queue a message to set the property
957       BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
958       break;
959     }
960
961     case Property::INTEGER:
962     {
963       const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
964       DALI_ASSERT_DEBUG( NULL != property );
965
966       // property is being used in a separate thread; queue a message to set the property
967       BakeMessage<int>( GetEventThreadServices(), *property, value.Get<int>() );
968       break;
969     }
970
971     case Property::VECTOR2:
972     {
973       const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
974       DALI_ASSERT_DEBUG( NULL != property );
975
976       // property is being used in a separate thread; queue a message to set the property
977       BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
978       break;
979     }
980
981     case Property::VECTOR3:
982     {
983       const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
984       DALI_ASSERT_DEBUG( NULL != property );
985
986       // property is being used in a separate thread; queue a message to set the property
987       BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
988       break;
989     }
990
991     case Property::VECTOR4:
992     {
993       const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
994       DALI_ASSERT_DEBUG( NULL != property );
995
996       // property is being used in a separate thread; queue a message to set the property
997       BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
998       break;
999     }
1000
1001     case Property::ROTATION:
1002     {
1003       const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
1004       DALI_ASSERT_DEBUG( NULL != property );
1005
1006       // property is being used in a separate thread; queue a message to set the property
1007       BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
1008       break;
1009     }
1010
1011     case Property::MATRIX:
1012     {
1013       const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
1014       DALI_ASSERT_DEBUG( NULL != property );
1015
1016       // property is being used in a separate thread; queue a message to set the property
1017       BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
1018       break;
1019     }
1020
1021     case Property::MATRIX3:
1022     {
1023       const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
1024       DALI_ASSERT_DEBUG( NULL != property );
1025
1026       // property is being used in a separate thread; queue a message to set the property
1027       BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
1028       break;
1029     }
1030
1031     default:
1032     {
1033       // non-animatable scene graph property, do nothing
1034     }
1035   }
1036 }
1037
1038 const TypeInfo* Object::GetTypeInfo() const
1039 {
1040   if ( !mTypeInfo )
1041   {
1042     // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1043     // especially as the type-info does not change during the life-time of an application
1044
1045     Dali::TypeInfo typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1046     if ( typeInfoHandle )
1047     {
1048       mTypeInfo = &GetImplementation( typeInfoHandle );
1049     }
1050   }
1051
1052   return mTypeInfo;
1053 }
1054
1055 void Object::RemoveConstraint( ActiveConstraint& constraint, bool isInScenegraph )
1056 {
1057   // guard against constraint sending messages during core destruction
1058   if ( Stage::IsInstalled() )
1059   {
1060     if( isInScenegraph )
1061     {
1062       ActiveConstraintBase& baseConstraint = GetImplementation( constraint );
1063       baseConstraint.BeginRemove();
1064     }
1065   }
1066 }
1067
1068 void Object::RemoveConstraint( Dali::ActiveConstraint activeConstraint )
1069 {
1070   // guard against constraint sending messages during core destruction
1071   if( mConstraints && Stage::IsInstalled() )
1072   {
1073     bool isInSceneGraph( NULL != GetSceneObject() );
1074
1075     ActiveConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), activeConstraint ) );
1076     if( it !=  mConstraints->end() )
1077     {
1078       RemoveConstraint( *it, isInSceneGraph );
1079       mConstraints->erase( it );
1080     }
1081   }
1082 }
1083
1084 void Object::RemoveConstraints( unsigned int tag )
1085 {
1086   // guard against constraint sending messages during core destruction
1087   if( mConstraints && Stage::IsInstalled() )
1088   {
1089     bool isInSceneGraph( NULL != GetSceneObject() );
1090
1091     ActiveConstraintIter iter( mConstraints->begin() );
1092     while(iter != mConstraints->end() )
1093     {
1094       ActiveConstraintBase& constraint = GetImplementation( *iter );
1095       if( constraint.GetTag() == tag )
1096       {
1097         RemoveConstraint( *iter, isInSceneGraph );
1098         iter = mConstraints->erase( iter );
1099       }
1100       else
1101       {
1102         ++iter;
1103       }
1104     }
1105   }
1106 }
1107
1108 void Object::RemoveConstraints()
1109 {
1110   // guard against constraint sending messages during core destruction
1111   if( mConstraints && Stage::IsInstalled() )
1112   {
1113     // If we have nothing in the scene-graph, just clear constraint containers
1114     const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
1115     if ( NULL != propertyOwner )
1116     {
1117       const ActiveConstraintConstIter endIter = mConstraints->end();
1118       for ( ActiveConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
1119       {
1120         RemoveConstraint( *iter, true );
1121       }
1122     }
1123
1124     delete mConstraints;
1125     mConstraints = NULL;
1126   }
1127 }
1128
1129 void Object::SetTypeInfo( const TypeInfo* typeInfo )
1130 {
1131   mTypeInfo = typeInfo;
1132 }
1133
1134 Object::~Object()
1135 {
1136   // Notification for this object's constraints
1137   // (note that the ActiveConstraint handles may outlive the Object)
1138   if( mConstraints )
1139   {
1140     const ActiveConstraintConstIter endIter = mConstraints->end();
1141     for ( ActiveConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
1142     {
1143       ActiveConstraintBase& baseConstraint = GetImplementation( *iter );
1144       baseConstraint.OnParentDestroyed();
1145     }
1146   }
1147
1148   // Notification for observers
1149   for( ConstObserverIter iter = mObservers.Begin(), endIter =  mObservers.End(); iter != endIter; ++iter)
1150   {
1151     (*iter)->ObjectDestroyed(*this);
1152   }
1153
1154   delete mConstraints;
1155   delete mPropertyNotifications;
1156 }
1157
1158 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1159 {
1160   CustomPropertyMetadata* property( NULL );
1161   int arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1162   if( arrayIndex >= 0 )
1163   {
1164     if( arrayIndex < (int)mCustomProperties.Count() ) // we can only access the first 2 billion custom properties
1165     {
1166       property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1167     }
1168   }
1169   return property;
1170 }
1171
1172 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1173 {
1174   for ( int arrayIndex = 0; arrayIndex < (int)mAnimatableProperties.Count(); arrayIndex++ )
1175   {
1176     AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( mAnimatableProperties[ arrayIndex ] );
1177     if( property->index == index )
1178     {
1179       return property;
1180     }
1181   }
1182   return NULL;
1183 }
1184
1185 } // namespace Internal
1186
1187 } // namespace Dali