[dali_1.0.39] Merge branch 'tizen'
[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   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
359   {
360     SetDefaultProperty( index, propertyValue );
361   }
362   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
363   {
364     const TypeInfo* typeInfo( GetTypeInfo() );
365     if ( typeInfo )
366     {
367       typeInfo->SetProperty( this, index, propertyValue );
368     }
369     else
370     {
371       DALI_LOG_ERROR("Cannot find property index\n");
372     }
373   }
374   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
375   {
376     // check whether the animatable property is registered already, if not then register one.
377     AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
378     if(!animatableProperty)
379     {
380       const TypeInfo* typeInfo( GetTypeInfo() );
381       if (!typeInfo)
382       {
383         DALI_LOG_ERROR("Cannot find property index\n");
384       }
385       else if ( Property::INVALID_INDEX == RegisterSceneGraphProperty( typeInfo->GetPropertyName( index ), index, propertyValue ) )
386       {
387         DALI_LOG_ERROR("Cannot register property\n");
388       }
389     }
390     else
391     {
392       // set the scene graph property value
393       SetSceneGraphProperty( index, *animatableProperty, propertyValue );
394     }
395   }
396   else
397   {
398     CustomPropertyMetadata* custom = FindCustomProperty( index );
399     if( custom )
400     {
401       if( custom->IsAnimatable() )
402       {
403         // set the scene graph property value
404         SetSceneGraphProperty( index, *custom, propertyValue );
405       }
406       else if( custom->IsWritable() )
407       {
408         custom->value = propertyValue;
409         OnPropertySet(index, propertyValue);
410       }
411       // trying to set value on read only property is no-op
412     }
413     else
414     {
415       DALI_LOG_ERROR("Invalid property index\n");
416     }
417   }
418 }
419
420 Property::Value Object::GetProperty(Property::Index index) const
421 {
422   DALI_ASSERT_ALWAYS( index > Property::INVALID_INDEX && "Property index is out of bounds" );
423
424   Property::Value value;
425
426   if ( index < DEFAULT_PROPERTY_MAX_COUNT )
427   {
428     value = GetDefaultProperty( index );
429   }
430   else if ( ( index >= PROPERTY_REGISTRATION_START_INDEX ) && ( index <= PROPERTY_REGISTRATION_MAX_INDEX ) )
431   {
432     const TypeInfo* typeInfo( GetTypeInfo() );
433     if ( typeInfo )
434     {
435       value = typeInfo->GetProperty( this, index );
436     }
437     else
438     {
439       DALI_LOG_ERROR("Cannot find property index\n");
440     }
441   }
442   else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
443   {
444     // check whether the animatable property is registered already, if not then register one.
445     AnimatablePropertyMetadata* animatableProperty = FindAnimatableProperty( index );
446     if(!animatableProperty)
447     {
448       const TypeInfo* typeInfo( GetTypeInfo() );
449       if (typeInfo)
450       {
451         if(Property::INVALID_INDEX != RegisterSceneGraphProperty(typeInfo->GetPropertyName(index), index, Property::Value(typeInfo->GetPropertyType(index))))
452         {
453           value = Property::Value(typeInfo->GetPropertyType(index)); // Return an initialized property value according to the type
454         }
455         else
456         {
457           DALI_LOG_ERROR("Cannot register property\n");
458         }
459       }
460       else
461       {
462         DALI_LOG_ERROR("Cannot find property index\n");
463       }
464     }
465     else
466     {
467       // get the animatable property value
468       value = GetPropertyValue( animatableProperty );
469     }
470   }
471   else if(mCustomProperties.Count() > 0)
472   {
473     CustomPropertyMetadata* custom = FindCustomProperty( index );
474     if(custom)
475     {
476       // get the custom property value
477       value = GetPropertyValue( custom );
478     }
479     else
480     {
481       DALI_LOG_ERROR("Invalid property index\n");
482     }
483   } // if custom
484
485   return value;
486 }
487
488 void Object::GetPropertyIndices( Property::IndexContainer& indices ) const
489 {
490   indices.clear();
491
492   // Default Properties
493   GetDefaultPropertyIndices( indices );
494
495   // Manual Properties
496   const TypeInfo* typeInfo( GetTypeInfo() );
497   if ( typeInfo )
498   {
499     typeInfo->GetPropertyIndices( indices );
500   }
501
502   // Custom Properties
503   if ( mCustomProperties.Count() > 0 )
504   {
505     indices.reserve( indices.size() + mCustomProperties.Count() );
506
507     PropertyMetadataLookup::ConstIterator iter = mCustomProperties.Begin();
508     const PropertyMetadataLookup::ConstIterator endIter = mCustomProperties.End();
509     int i=0;
510     for ( ; iter != endIter; ++iter, ++i )
511     {
512       indices.push_back( PROPERTY_CUSTOM_START_INDEX + i );
513     }
514   }
515 }
516
517 Property::Index Object::RegisterSceneGraphProperty(const std::string& name, Property::Index index, const Property::Value& propertyValue) const
518 {
519   // Create a new property
520   Dali::Internal::OwnerPointer<PropertyBase> newProperty;
521
522   switch ( propertyValue.GetType() )
523   {
524     case Property::BOOLEAN:
525     {
526       newProperty = new AnimatableProperty<bool>( propertyValue.Get<bool>() );
527       break;
528     }
529
530     case Property::INTEGER:
531     {
532       newProperty = new AnimatableProperty<int>( propertyValue.Get<int>() );
533       break;
534     }
535
536     case Property::UNSIGNED_INTEGER:
537     {
538       newProperty = new AnimatableProperty<unsigned int>( propertyValue.Get<unsigned int>() );
539       break;
540     }
541
542     case Property::FLOAT:
543     {
544       newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
545       break;
546     }
547
548     case Property::VECTOR2:
549     {
550       newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
551       break;
552     }
553
554     case Property::VECTOR3:
555     {
556       newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
557       break;
558     }
559
560     case Property::VECTOR4:
561     {
562       newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
563       break;
564     }
565
566     case Property::MATRIX:
567     {
568       newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
569       break;
570     }
571
572     case Property::MATRIX3:
573     {
574       newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
575       break;
576     }
577
578     case Property::ROTATION:
579     {
580       newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
581       break;
582     }
583
584     case Property::RECTANGLE:
585     case Property::STRING:
586     case Property::ARRAY:
587     case Property::MAP:
588     {
589       DALI_LOG_WARNING( "Property Type %d\n", propertyValue.GetType() );
590       DALI_ASSERT_ALWAYS( !"PropertyType is not animatable" );
591       break;
592     }
593
594     default:
595     {
596       DALI_LOG_WARNING( "Property Type %d\n", propertyValue.GetType() );
597       DALI_ASSERT_ALWAYS( !"PropertyType enumeration is out of bounds" );
598       break;
599     }
600   }
601
602   // get the scene property owner from derived class
603   const SceneGraph::PropertyOwner* scenePropertyOwner = GetPropertyOwner();
604   // we can only pass properties to scene graph side if there is a scene object
605   if( scenePropertyOwner )
606   {
607     // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
608     const PropertyBase* property = newProperty.Get();
609     if(index >= PROPERTY_CUSTOM_START_INDEX)
610     {
611       mCustomProperties.PushBack( new CustomPropertyMetadata( name, propertyValue.GetType(), property ) );
612     }
613     else
614     {
615       mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, propertyValue.GetType(), property ) );
616     }
617
618     // queue a message to add the property
619     InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *scenePropertyOwner, newProperty.Release() ); // Message takes ownership
620
621     // notify the derived class (optional) method in case it needs to do some more work on the new property
622     // note! have to use the local pointer as OwnerPointer now points to NULL as it handed over its ownership
623     NotifyScenePropertyInstalled( *property, name, index );
624
625     return index;
626   }
627   else
628   {
629     // property was orphaned and killed so return invalid index
630     return Property::INVALID_INDEX;
631   }
632 }
633
634 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue)
635 {
636   return RegisterSceneGraphProperty(name, PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count(), propertyValue);
637 }
638
639 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode)
640 {
641   Property::Index index = Property::INVALID_INDEX;
642
643   if(Property::ANIMATABLE == accessMode)
644   {
645     index = RegisterProperty(name, propertyValue);
646   }
647   else
648   {
649     // Add entry to the property lookup
650     index = PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count();
651     mCustomProperties.PushBack( new CustomPropertyMetadata( name, propertyValue, accessMode ) );
652   }
653
654   return index;
655 }
656
657 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index,
658                                                                 int componentIndex,
659                                                                 const Dali::PropertyCondition& condition)
660 {
661   if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
662   {
663     if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
664     {
665       DALI_ASSERT_ALWAYS( false && "Property notification added to event side only property." );
666     }
667     else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
668     {
669       // check whether the animatable property is registered already, if not then register one.
670       AnimatablePropertyMetadata* animatable = FindAnimatableProperty( index );
671       if( !animatable )
672       {
673         const TypeInfo* typeInfo( GetTypeInfo() );
674         if ( typeInfo )
675         {
676           if( Property::INVALID_INDEX != RegisterSceneGraphProperty( typeInfo->GetPropertyName( index ), index, Property::Value( typeInfo->GetPropertyType( index ) ) ) )
677           {
678             animatable = FindAnimatableProperty( index );
679           }
680         }
681       }
682       DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
683     }
684     else if ( mCustomProperties.Count() > 0 )
685     {
686       CustomPropertyMetadata* custom = FindCustomProperty( index );
687       DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
688       DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
689     }
690   }
691
692   Dali::Handle self(this);
693   Property target( self, index );
694
695   PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
696   Dali::PropertyNotification propertyNotification(internal.Get());
697
698   if( !mPropertyNotifications )
699   {
700     mPropertyNotifications = new PropertyNotificationContainer;
701   }
702   mPropertyNotifications->push_back(propertyNotification);
703
704   return propertyNotification;
705 }
706
707 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
708 {
709   if( mPropertyNotifications )
710   {
711     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
712     while(iter != mPropertyNotifications->end() )
713     {
714       if(*iter == propertyNotification)
715       {
716         mPropertyNotifications->erase(iter);
717         // As we can't ensure all references are removed, we can just disable
718         // the notification.
719         GetImplementation(propertyNotification).Disable();
720         return;
721       }
722       ++iter;
723     }
724   }
725 }
726
727 void Object::RemovePropertyNotifications()
728 {
729   if( mPropertyNotifications )
730   {
731     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
732     while(iter != mPropertyNotifications->end() )
733     {
734       // As we can't ensure all references are removed, we can just disable
735       // the notification.
736       GetImplementation(*iter).Disable();
737       ++iter;
738     }
739
740     mPropertyNotifications->clear();
741   }
742 }
743
744 void Object::EnablePropertyNotifications()
745 {
746   if( mPropertyNotifications )
747   {
748     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
749     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
750
751     for( ; iter != endIter; ++iter )
752     {
753       GetImplementation(*iter).Enable();
754     }
755   }
756 }
757
758 void Object::DisablePropertyNotifications()
759 {
760   if( mPropertyNotifications )
761   {
762     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
763     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
764
765     for( ; iter != endIter; ++iter )
766     {
767       GetImplementation(*iter).Disable();
768     }
769   }
770 }
771
772 Property::Value Object::GetPropertyValue( const PropertyMetadata* entry ) const
773 {
774   Property::Value value;
775
776   DALI_ASSERT_ALWAYS( entry && "Invalid property metadata" );
777
778   if( !entry->IsAnimatable() )
779   {
780     value = entry->value;
781   }
782   else
783   {
784     BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
785
786     switch ( entry->type )
787     {
788       case Property::BOOLEAN:
789       {
790         const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry->GetSceneGraphProperty() );
791         DALI_ASSERT_DEBUG( NULL != property );
792
793         value = (*property)[ bufferIndex ];
794         break;
795       }
796
797       case Property::INTEGER:
798       {
799         const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry->GetSceneGraphProperty() );
800         DALI_ASSERT_DEBUG( NULL != property );
801
802         value = (*property)[ bufferIndex ];
803         break;
804       }
805
806       case Property::UNSIGNED_INTEGER:
807       {
808         const AnimatableProperty<unsigned int>* property = dynamic_cast< const AnimatableProperty<unsigned int>* >( entry->GetSceneGraphProperty() );
809         DALI_ASSERT_DEBUG( NULL != property );
810
811         value = (*property)[ bufferIndex ];
812         break;
813       }
814
815       case Property::FLOAT:
816       {
817         const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry->GetSceneGraphProperty() );
818         DALI_ASSERT_DEBUG( NULL != property );
819
820         value = (*property)[ bufferIndex ];
821         break;
822       }
823
824       case Property::VECTOR2:
825       {
826         const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry->GetSceneGraphProperty() );
827         DALI_ASSERT_DEBUG( NULL != property );
828
829         value = (*property)[ bufferIndex ];
830         break;
831       }
832
833       case Property::VECTOR3:
834       {
835         const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry->GetSceneGraphProperty() );
836         DALI_ASSERT_DEBUG( NULL != property );
837
838         value = (*property)[ bufferIndex ];
839         break;
840       }
841
842       case Property::VECTOR4:
843       {
844         const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry->GetSceneGraphProperty() );
845         DALI_ASSERT_DEBUG( NULL != property );
846
847         value = (*property)[ bufferIndex ];
848         break;
849       }
850
851       case Property::MATRIX:
852       {
853         const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry->GetSceneGraphProperty() );
854         DALI_ASSERT_DEBUG( NULL != property );
855
856         value = (*property)[ bufferIndex ];
857         break;
858       }
859
860       case Property::MATRIX3:
861       {
862         const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry->GetSceneGraphProperty() );
863         DALI_ASSERT_DEBUG( NULL != property );
864
865         value = (*property)[ bufferIndex ];
866         break;
867       }
868
869       case Property::ROTATION:
870       {
871         const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry->GetSceneGraphProperty() );
872         DALI_ASSERT_DEBUG( NULL != property );
873
874         value = (*property)[ bufferIndex ];
875         break;
876       }
877
878       default:
879       {
880         DALI_ASSERT_ALWAYS( false && "PropertyType enumeration is out of bounds" );
881         break;
882       }
883     } // switch(type)
884   } // if animatable
885
886   return value;
887 }
888
889 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
890 {
891   switch ( entry.type )
892   {
893     case Property::BOOLEAN:
894     {
895       const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
896       DALI_ASSERT_DEBUG( NULL != property );
897
898       // property is being used in a separate thread; queue a message to set the property
899       BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
900       break;
901     }
902
903     case Property::INTEGER:
904     {
905       const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
906       DALI_ASSERT_DEBUG( NULL != property );
907
908       // property is being used in a separate thread; queue a message to set the property
909       BakeMessage<int>( GetEventThreadServices(), *property, value.Get<int>() );
910       break;
911     }
912
913     case Property::UNSIGNED_INTEGER:
914     {
915       const AnimatableProperty<unsigned int>* property = dynamic_cast< const AnimatableProperty<unsigned int>* >( entry.GetSceneGraphProperty() );
916       DALI_ASSERT_DEBUG( NULL != property );
917
918       // property is being used in a separate thread; queue a message to set the property
919       BakeMessage<unsigned int>( GetEventThreadServices(), *property, value.Get<unsigned int>() );
920       break;
921     }
922
923     case Property::FLOAT:
924     {
925       const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
926       DALI_ASSERT_DEBUG( NULL != property );
927
928       // property is being used in a separate thread; queue a message to set the property
929       BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
930       break;
931     }
932
933     case Property::VECTOR2:
934     {
935       const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
936       DALI_ASSERT_DEBUG( NULL != property );
937
938       // property is being used in a separate thread; queue a message to set the property
939       BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
940       break;
941     }
942
943     case Property::VECTOR3:
944     {
945       const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
946       DALI_ASSERT_DEBUG( NULL != property );
947
948       // property is being used in a separate thread; queue a message to set the property
949       BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
950       break;
951     }
952
953     case Property::VECTOR4:
954     {
955       const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
956       DALI_ASSERT_DEBUG( NULL != property );
957
958       // property is being used in a separate thread; queue a message to set the property
959       BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
960       break;
961     }
962
963     case Property::ROTATION:
964     {
965       const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
966       DALI_ASSERT_DEBUG( NULL != property );
967
968       // property is being used in a separate thread; queue a message to set the property
969       BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
970       break;
971     }
972
973     case Property::MATRIX:
974     {
975       const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
976       DALI_ASSERT_DEBUG( NULL != property );
977
978       // property is being used in a separate thread; queue a message to set the property
979       BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
980       break;
981     }
982
983     case Property::MATRIX3:
984     {
985       const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
986       DALI_ASSERT_DEBUG( NULL != property );
987
988       // property is being used in a separate thread; queue a message to set the property
989       BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
990       break;
991     }
992
993     default:
994     {
995       // non-animatable scene graph property, do nothing
996     }
997   }
998 }
999
1000 const TypeInfo* Object::GetTypeInfo() const
1001 {
1002   if ( !mTypeInfo )
1003   {
1004     // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
1005     // especially as the type-info does not change during the life-time of an application
1006
1007     Dali::TypeInfo typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
1008     if ( typeInfoHandle )
1009     {
1010       mTypeInfo = &GetImplementation( typeInfoHandle );
1011     }
1012   }
1013
1014   return mTypeInfo;
1015 }
1016
1017 void Object::ApplyConstraint( ConstraintBase& constraint )
1018 {
1019   if( !mConstraints )
1020   {
1021     mConstraints = new ConstraintContainer;
1022   }
1023   mConstraints->push_back( Dali::Constraint( &constraint ) );
1024 }
1025
1026 void Object::RemoveConstraint( ConstraintBase& constraint )
1027 {
1028   // NULL if the Constraint sources are destroyed before Constraint::Apply()
1029   if( mConstraints )
1030   {
1031     ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
1032     if( it != mConstraints->end() )
1033     {
1034       mConstraints->erase( it );
1035     }
1036   }
1037 }
1038
1039 void Object::RemoveConstraints()
1040 {
1041   // guard against constraint sending messages during core destruction
1042   if( mConstraints && Stage::IsInstalled() )
1043   {
1044     // If we have nothing in the scene-graph, just clear constraint containers
1045     const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
1046     if ( NULL != propertyOwner )
1047     {
1048       const ConstraintConstIter endIter = mConstraints->end();
1049       for ( ConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
1050       {
1051         GetImplementation( *iter ).RemoveInternal();
1052       }
1053     }
1054
1055     delete mConstraints;
1056     mConstraints = NULL;
1057   }
1058 }
1059
1060 void Object::RemoveConstraints( unsigned int tag )
1061 {
1062   // guard against constraint sending messages during core destruction
1063   if( mConstraints && Stage::IsInstalled() )
1064   {
1065     ConstraintIter iter( mConstraints->begin() );
1066     while(iter != mConstraints->end() )
1067     {
1068       ConstraintBase& constraint = GetImplementation( *iter );
1069       if( constraint.GetTag() == tag )
1070       {
1071         GetImplementation( *iter ).RemoveInternal();
1072         iter = mConstraints->erase( iter );
1073       }
1074       else
1075       {
1076         ++iter;
1077       }
1078     }
1079
1080     if ( mConstraints->empty() )
1081     {
1082       delete mConstraints;
1083       mConstraints = NULL;
1084     }
1085   }
1086 }
1087
1088 void Object::SetTypeInfo( const TypeInfo* typeInfo )
1089 {
1090   mTypeInfo = typeInfo;
1091 }
1092
1093 Object::~Object()
1094 {
1095   // Notification for observers
1096   for( ConstObserverIter iter = mObservers.Begin(), endIter =  mObservers.End(); iter != endIter; ++iter)
1097   {
1098     (*iter)->ObjectDestroyed(*this);
1099   }
1100
1101   delete mConstraints;
1102   delete mPropertyNotifications;
1103 }
1104
1105 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1106 {
1107   CustomPropertyMetadata* property( NULL );
1108   int arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1109   if( arrayIndex >= 0 )
1110   {
1111     if( arrayIndex < (int)mCustomProperties.Count() ) // we can only access the first 2 billion custom properties
1112     {
1113       property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1114     }
1115   }
1116   return property;
1117 }
1118
1119 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1120 {
1121   for ( int arrayIndex = 0; arrayIndex < (int)mAnimatableProperties.Count(); arrayIndex++ )
1122   {
1123     AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( mAnimatableProperties[ arrayIndex ] );
1124     if( property->index == index )
1125     {
1126       return property;
1127     }
1128   }
1129   return NULL;
1130 }
1131
1132 } // namespace Internal
1133
1134 } // namespace Dali