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