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