Merge remote-tracking branch 'origin/tizen' into new_text
[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::FLOAT:
531     {
532       newProperty = new AnimatableProperty<float>( propertyValue.Get<float>() );
533       break;
534     }
535
536     case Property::INTEGER:
537     {
538       newProperty = new AnimatableProperty<int>( propertyValue.Get<int>() );
539       break;
540     }
541
542     case Property::VECTOR2:
543     {
544       newProperty = new AnimatableProperty<Vector2>( propertyValue.Get<Vector2>() );
545       break;
546     }
547
548     case Property::VECTOR3:
549     {
550       newProperty = new AnimatableProperty<Vector3>( propertyValue.Get<Vector3>() );
551       break;
552     }
553
554     case Property::VECTOR4:
555     {
556       newProperty = new AnimatableProperty<Vector4>( propertyValue.Get<Vector4>() );
557       break;
558     }
559
560     case Property::MATRIX:
561     {
562       newProperty = new AnimatableProperty<Matrix>( propertyValue.Get<Matrix>() );
563       break;
564     }
565
566     case Property::MATRIX3:
567     {
568       newProperty = new AnimatableProperty<Matrix3>( propertyValue.Get<Matrix3>() );
569       break;
570     }
571
572     case Property::ROTATION:
573     {
574       newProperty = new AnimatableProperty<Quaternion>( propertyValue.Get<Quaternion>() );
575       break;
576     }
577
578     case Property::UNSIGNED_INTEGER:
579     case Property::RECTANGLE:
580     case Property::STRING:
581     case Property::ARRAY:
582     case Property::MAP:
583     {
584       DALI_LOG_WARNING( "Property Type %d\n", propertyValue.GetType() );
585       DALI_ASSERT_ALWAYS( !"PropertyType is not animatable" );
586       break;
587     }
588
589     default:
590     {
591       DALI_LOG_WARNING( "Property Type %d\n", propertyValue.GetType() );
592       DALI_ASSERT_ALWAYS( !"PropertyType enumeration is out of bounds" );
593       break;
594     }
595   }
596
597   // get the scene property owner from derived class
598   const SceneGraph::PropertyOwner* scenePropertyOwner = GetPropertyOwner();
599   // we can only pass properties to scene graph side if there is a scene object
600   if( scenePropertyOwner )
601   {
602     // keep a local pointer to the property as the OwnerPointer will pass its copy to the message
603     const PropertyBase* property = newProperty.Get();
604     if(index >= PROPERTY_CUSTOM_START_INDEX)
605     {
606       mCustomProperties.PushBack( new CustomPropertyMetadata( name, propertyValue.GetType(), property ) );
607     }
608     else
609     {
610       mAnimatableProperties.PushBack( new AnimatablePropertyMetadata( index, propertyValue.GetType(), property ) );
611     }
612
613     // queue a message to add the property
614     InstallCustomPropertyMessage( const_cast<EventThreadServices&>(GetEventThreadServices()), *scenePropertyOwner, newProperty.Release() ); // Message takes ownership
615
616     // notify the derived class (optional) method in case it needs to do some more work on the new property
617     // note! have to use the local pointer as OwnerPointer now points to NULL as it handed over its ownership
618     NotifyScenePropertyInstalled( *property, name, index );
619
620     return index;
621   }
622   else
623   {
624     // property was orphaned and killed so return invalid index
625     return Property::INVALID_INDEX;
626   }
627 }
628
629 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue)
630 {
631   return RegisterSceneGraphProperty(name, PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count(), propertyValue);
632 }
633
634 Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode)
635 {
636   Property::Index index = Property::INVALID_INDEX;
637
638   if(Property::ANIMATABLE == accessMode)
639   {
640     index = RegisterProperty(name, propertyValue);
641   }
642   else
643   {
644     // Add entry to the property lookup
645     index = PROPERTY_CUSTOM_START_INDEX + mCustomProperties.Count();
646     mCustomProperties.PushBack( new CustomPropertyMetadata( name, propertyValue, accessMode ) );
647   }
648
649   return index;
650 }
651
652 Dali::PropertyNotification Object::AddPropertyNotification(Property::Index index,
653                                                                 int componentIndex,
654                                                                 const Dali::PropertyCondition& condition)
655 {
656   if ( index >= DEFAULT_PROPERTY_MAX_COUNT )
657   {
658     if ( index <= PROPERTY_REGISTRATION_MAX_INDEX )
659     {
660       DALI_ASSERT_ALWAYS( false && "Property notification added to event side only property." );
661     }
662     else if ( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
663     {
664       // check whether the animatable property is registered already, if not then register one.
665       AnimatablePropertyMetadata* animatable = FindAnimatableProperty( index );
666       if( !animatable )
667       {
668         const TypeInfo* typeInfo( GetTypeInfo() );
669         if ( typeInfo )
670         {
671           if( Property::INVALID_INDEX != RegisterSceneGraphProperty( typeInfo->GetPropertyName( index ), index, Property::Value( typeInfo->GetPropertyType( index ) ) ) )
672           {
673             animatable = FindAnimatableProperty( index );
674           }
675         }
676       }
677       DALI_ASSERT_ALWAYS( animatable && "Property index is invalid" );
678     }
679     else if ( mCustomProperties.Count() > 0 )
680     {
681       CustomPropertyMetadata* custom = FindCustomProperty( index );
682       DALI_ASSERT_ALWAYS( custom && "Invalid property index" );
683       DALI_ASSERT_ALWAYS( custom->IsAnimatable() && "Property notification added to event side only property." );
684     }
685   }
686
687   Dali::Handle self(this);
688   Property target( self, index );
689
690   PropertyNotificationPtr internal = PropertyNotification::New( target, componentIndex, condition );
691   Dali::PropertyNotification propertyNotification(internal.Get());
692
693   if( !mPropertyNotifications )
694   {
695     mPropertyNotifications = new PropertyNotificationContainer;
696   }
697   mPropertyNotifications->push_back(propertyNotification);
698
699   return propertyNotification;
700 }
701
702 void Object::RemovePropertyNotification(Dali::PropertyNotification propertyNotification)
703 {
704   if( mPropertyNotifications )
705   {
706     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
707     while(iter != mPropertyNotifications->end() )
708     {
709       if(*iter == propertyNotification)
710       {
711         mPropertyNotifications->erase(iter);
712         // As we can't ensure all references are removed, we can just disable
713         // the notification.
714         GetImplementation(propertyNotification).Disable();
715         return;
716       }
717       ++iter;
718     }
719   }
720 }
721
722 void Object::RemovePropertyNotifications()
723 {
724   if( mPropertyNotifications )
725   {
726     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
727     while(iter != mPropertyNotifications->end() )
728     {
729       // As we can't ensure all references are removed, we can just disable
730       // the notification.
731       GetImplementation(*iter).Disable();
732       ++iter;
733     }
734
735     mPropertyNotifications->clear();
736   }
737 }
738
739 void Object::EnablePropertyNotifications()
740 {
741   if( mPropertyNotifications )
742   {
743     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
744     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
745
746     for( ; iter != endIter; ++iter )
747     {
748       GetImplementation(*iter).Enable();
749     }
750   }
751 }
752
753 void Object::DisablePropertyNotifications()
754 {
755   if( mPropertyNotifications )
756   {
757     PropertyNotificationContainerIter iter = mPropertyNotifications->begin();
758     PropertyNotificationContainerIter endIter = mPropertyNotifications->end();
759
760     for( ; iter != endIter; ++iter )
761     {
762       GetImplementation(*iter).Disable();
763     }
764   }
765 }
766
767 Property::Value Object::GetPropertyValue( const PropertyMetadata* entry ) const
768 {
769   Property::Value value;
770
771   DALI_ASSERT_ALWAYS( entry && "Invalid property metadata" );
772
773   if( !entry->IsAnimatable() )
774   {
775     value = entry->value;
776   }
777   else
778   {
779     BufferIndex bufferIndex( GetEventThreadServices().GetEventBufferIndex() );
780
781     switch ( entry->type )
782     {
783       case Property::BOOLEAN:
784       {
785         const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry->GetSceneGraphProperty() );
786         DALI_ASSERT_DEBUG( NULL != property );
787
788         value = (*property)[ bufferIndex ];
789         break;
790       }
791
792       case Property::FLOAT:
793       {
794         const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry->GetSceneGraphProperty() );
795         DALI_ASSERT_DEBUG( NULL != property );
796
797         value = (*property)[ bufferIndex ];
798         break;
799       }
800
801       case Property::INTEGER:
802       {
803         const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry->GetSceneGraphProperty() );
804         DALI_ASSERT_DEBUG( NULL != property );
805
806         value = (*property)[ bufferIndex ];
807         break;
808       }
809
810       case Property::VECTOR2:
811       {
812         const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry->GetSceneGraphProperty() );
813         DALI_ASSERT_DEBUG( NULL != property );
814
815         value = (*property)[ bufferIndex ];
816         break;
817       }
818
819       case Property::VECTOR3:
820       {
821         const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry->GetSceneGraphProperty() );
822         DALI_ASSERT_DEBUG( NULL != property );
823
824         value = (*property)[ bufferIndex ];
825         break;
826       }
827
828       case Property::VECTOR4:
829       {
830         const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry->GetSceneGraphProperty() );
831         DALI_ASSERT_DEBUG( NULL != property );
832
833         value = (*property)[ bufferIndex ];
834         break;
835       }
836
837       case Property::MATRIX:
838       {
839         const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry->GetSceneGraphProperty() );
840         DALI_ASSERT_DEBUG( NULL != property );
841
842         value = (*property)[ bufferIndex ];
843         break;
844       }
845
846       case Property::MATRIX3:
847       {
848         const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry->GetSceneGraphProperty() );
849         DALI_ASSERT_DEBUG( NULL != property );
850
851         value = (*property)[ bufferIndex ];
852         break;
853       }
854
855       case Property::ROTATION:
856       {
857         const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry->GetSceneGraphProperty() );
858         DALI_ASSERT_DEBUG( NULL != property );
859
860         value = (*property)[ bufferIndex ];
861         break;
862       }
863
864       default:
865       {
866         DALI_ASSERT_ALWAYS( false && "PropertyType enumeration is out of bounds" );
867         break;
868       }
869     } // switch(type)
870   } // if animatable
871
872   return value;
873 }
874
875 void Object::SetSceneGraphProperty( Property::Index index, const PropertyMetadata& entry, const Property::Value& value )
876 {
877   switch ( entry.type )
878   {
879     case Property::BOOLEAN:
880     {
881       const AnimatableProperty<bool>* property = dynamic_cast< const AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
882       DALI_ASSERT_DEBUG( NULL != property );
883
884       // property is being used in a separate thread; queue a message to set the property
885       BakeMessage<bool>( GetEventThreadServices(), *property, value.Get<bool>() );
886       break;
887     }
888
889     case Property::FLOAT:
890     {
891       const AnimatableProperty<float>* property = dynamic_cast< const AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
892       DALI_ASSERT_DEBUG( NULL != property );
893
894       // property is being used in a separate thread; queue a message to set the property
895       BakeMessage<float>( GetEventThreadServices(), *property, value.Get<float>() );
896       break;
897     }
898
899     case Property::INTEGER:
900     {
901       const AnimatableProperty<int>* property = dynamic_cast< const AnimatableProperty<int>* >( entry.GetSceneGraphProperty() );
902       DALI_ASSERT_DEBUG( NULL != property );
903
904       // property is being used in a separate thread; queue a message to set the property
905       BakeMessage<int>( GetEventThreadServices(), *property, value.Get<int>() );
906       break;
907     }
908
909     case Property::VECTOR2:
910     {
911       const AnimatableProperty<Vector2>* property = dynamic_cast< const AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
912       DALI_ASSERT_DEBUG( NULL != property );
913
914       // property is being used in a separate thread; queue a message to set the property
915       BakeMessage<Vector2>( GetEventThreadServices(), *property, value.Get<Vector2>() );
916       break;
917     }
918
919     case Property::VECTOR3:
920     {
921       const AnimatableProperty<Vector3>* property = dynamic_cast< const AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
922       DALI_ASSERT_DEBUG( NULL != property );
923
924       // property is being used in a separate thread; queue a message to set the property
925       BakeMessage<Vector3>( GetEventThreadServices(), *property, value.Get<Vector3>() );
926       break;
927     }
928
929     case Property::VECTOR4:
930     {
931       const AnimatableProperty<Vector4>* property = dynamic_cast< const AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
932       DALI_ASSERT_DEBUG( NULL != property );
933
934       // property is being used in a separate thread; queue a message to set the property
935       BakeMessage<Vector4>( GetEventThreadServices(), *property, value.Get<Vector4>() );
936       break;
937     }
938
939     case Property::ROTATION:
940     {
941       const AnimatableProperty<Quaternion>* property = dynamic_cast< const AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
942       DALI_ASSERT_DEBUG( NULL != property );
943
944       // property is being used in a separate thread; queue a message to set the property
945       BakeMessage<Quaternion>( GetEventThreadServices(), *property, value.Get<Quaternion>() );
946       break;
947     }
948
949     case Property::MATRIX:
950     {
951       const AnimatableProperty<Matrix>* property = dynamic_cast< const AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
952       DALI_ASSERT_DEBUG( NULL != property );
953
954       // property is being used in a separate thread; queue a message to set the property
955       BakeMessage<Matrix>( GetEventThreadServices(), *property, value.Get<Matrix>() );
956       break;
957     }
958
959     case Property::MATRIX3:
960     {
961       const AnimatableProperty<Matrix3>* property = dynamic_cast< const AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
962       DALI_ASSERT_DEBUG( NULL != property );
963
964       // property is being used in a separate thread; queue a message to set the property
965       BakeMessage<Matrix3>( GetEventThreadServices(), *property, value.Get<Matrix3>() );
966       break;
967     }
968
969     default:
970     {
971       // non-animatable scene graph property, do nothing
972     }
973   }
974 }
975
976 const TypeInfo* Object::GetTypeInfo() const
977 {
978   if ( !mTypeInfo )
979   {
980     // This uses a dynamic_cast so can be quite expensive so we only really want to do it once
981     // especially as the type-info does not change during the life-time of an application
982
983     Dali::TypeInfo typeInfoHandle = TypeRegistry::Get()->GetTypeInfo( this );
984     if ( typeInfoHandle )
985     {
986       mTypeInfo = &GetImplementation( typeInfoHandle );
987     }
988   }
989
990   return mTypeInfo;
991 }
992
993 void Object::ApplyConstraint( ConstraintBase& constraint )
994 {
995   if( !mConstraints )
996   {
997     mConstraints = new ConstraintContainer;
998   }
999   mConstraints->push_back( Dali::Constraint( &constraint ) );
1000 }
1001
1002 void Object::RemoveConstraint( ConstraintBase& constraint )
1003 {
1004   DALI_ASSERT_DEBUG( mConstraints );
1005
1006   ConstraintIter it( std::find( mConstraints->begin(), mConstraints->end(), Dali::Constraint( &constraint ) ) );
1007   if( it != mConstraints->end() )
1008   {
1009     mConstraints->erase( it );
1010   }
1011 }
1012
1013 void Object::RemoveConstraints()
1014 {
1015   // guard against constraint sending messages during core destruction
1016   if( mConstraints && Stage::IsInstalled() )
1017   {
1018     // If we have nothing in the scene-graph, just clear constraint containers
1019     const SceneGraph::PropertyOwner* propertyOwner = GetSceneObject();
1020     if ( NULL != propertyOwner )
1021     {
1022       const ConstraintConstIter endIter = mConstraints->end();
1023       for ( ConstraintIter iter = mConstraints->begin(); endIter != iter; ++iter )
1024       {
1025         GetImplementation( *iter ).RemoveInternal();
1026       }
1027     }
1028
1029     delete mConstraints;
1030     mConstraints = NULL;
1031   }
1032 }
1033
1034 void Object::RemoveConstraints( unsigned int tag )
1035 {
1036   // guard against constraint sending messages during core destruction
1037   if( mConstraints && Stage::IsInstalled() )
1038   {
1039     ConstraintIter iter( mConstraints->begin() );
1040     while(iter != mConstraints->end() )
1041     {
1042       ConstraintBase& constraint = GetImplementation( *iter );
1043       if( constraint.GetTag() == tag )
1044       {
1045         GetImplementation( *iter ).RemoveInternal();
1046         iter = mConstraints->erase( iter );
1047       }
1048       else
1049       {
1050         ++iter;
1051       }
1052     }
1053
1054     if ( mConstraints->empty() )
1055     {
1056       delete mConstraints;
1057       mConstraints = NULL;
1058     }
1059   }
1060 }
1061
1062 void Object::SetTypeInfo( const TypeInfo* typeInfo )
1063 {
1064   mTypeInfo = typeInfo;
1065 }
1066
1067 Object::~Object()
1068 {
1069   // Notification for observers
1070   for( ConstObserverIter iter = mObservers.Begin(), endIter =  mObservers.End(); iter != endIter; ++iter)
1071   {
1072     (*iter)->ObjectDestroyed(*this);
1073   }
1074
1075   delete mConstraints;
1076   delete mPropertyNotifications;
1077 }
1078
1079 CustomPropertyMetadata* Object::FindCustomProperty( Property::Index index ) const
1080 {
1081   CustomPropertyMetadata* property( NULL );
1082   int arrayIndex = index - PROPERTY_CUSTOM_START_INDEX;
1083   if( arrayIndex >= 0 )
1084   {
1085     if( arrayIndex < (int)mCustomProperties.Count() ) // we can only access the first 2 billion custom properties
1086     {
1087       property = static_cast<CustomPropertyMetadata*>(mCustomProperties[ arrayIndex ]);
1088     }
1089   }
1090   return property;
1091 }
1092
1093 AnimatablePropertyMetadata* Object::FindAnimatableProperty( Property::Index index ) const
1094 {
1095   for ( int arrayIndex = 0; arrayIndex < (int)mAnimatableProperties.Count(); arrayIndex++ )
1096   {
1097     AnimatablePropertyMetadata* property = static_cast<AnimatablePropertyMetadata*>( mAnimatableProperties[ arrayIndex ] );
1098     if( property->index == index )
1099     {
1100       return property;
1101     }
1102   }
1103   return NULL;
1104 }
1105
1106 } // namespace Internal
1107
1108 } // namespace Dali