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