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