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