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