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