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