Merge remote-tracking branch 'origin/tizen' into devel/new_mesh
[platform/core/uifw/dali-core.git] / dali / internal / event / common / type-info-impl.cpp
1 /*
2  * Copyright (c) 2015 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/type-info-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm> // std::find_if
23 #include <string>
24
25 // INTERNAL INCLUDES
26 #include <dali/integration-api/debug.h>
27 #include <dali/internal/event/common/type-registry-impl.h>
28 #include <dali/internal/event/common/object-impl.h>
29
30 using std::find_if;
31
32 namespace
33 {
34
35 /*
36  * Functor to find by given type for vector of pairs
37  */
38 template <typename S, typename T>
39 struct PairFinder
40 {
41   PairFinder(const S& find)
42   : mFind(find)
43   {
44   }
45
46   bool operator()(const T& p) const
47   {
48     return p.first == mFind;
49   }
50
51 private:
52
53   const S& mFind;
54 };
55
56 /**
57  * Functor to find a matching property name
58  */
59 template <typename T>
60 struct PropertyNameFinder
61 {
62   PropertyNameFinder( const std::string& find )
63   : mFind( find )
64   {
65   }
66
67   bool operator()(const T &p) const
68   {
69     return p.second.name == mFind;
70   }
71
72 private:
73
74   const std::string& mFind;
75 };
76
77 /**
78  * Functor to find a matching property component index
79  */
80 template <typename T>
81 struct PropertyComponentFinder
82 {
83   PropertyComponentFinder( Dali::Property::Index basePropertyIndex, const int find )
84   : mBasePropertyIndex( basePropertyIndex ),
85     mFind( find )
86   {
87   }
88
89   bool operator()(const T &p) const
90   {
91     return ( p.second.basePropertyIndex == mBasePropertyIndex && p.second.componentIndex == mFind );
92   }
93
94 private:
95
96   Dali::Property::Index mBasePropertyIndex;
97   const int mFind;
98 };
99
100 } // namespace anon
101
102 namespace Dali
103 {
104
105 namespace Internal
106 {
107
108 TypeInfo::TypeInfo(const std::string &name, const std::string &baseTypeName, Dali::TypeInfo::CreateFunction creator)
109   : mTypeName(name), mBaseTypeName(baseTypeName), mCreate(creator)
110 {
111   DALI_ASSERT_ALWAYS(!name.empty() && "Type info construction must have a name");
112   DALI_ASSERT_ALWAYS(!baseTypeName.empty() && "Type info construction must have a base type name");
113 }
114
115 TypeInfo::~TypeInfo()
116 {
117 }
118
119 BaseHandle TypeInfo::CreateInstance() const
120 {
121   BaseHandle ret;
122
123   if(mCreate)
124   {
125     ret = mCreate();
126
127     if ( ret )
128     {
129       BaseObject& handle = ret.GetBaseObject();
130       Object *object = dynamic_cast<Internal::Object*>(&handle);
131
132       if ( object )
133       {
134         object->SetTypeInfo( this );
135       }
136     }
137   }
138   return ret;
139 }
140
141 bool TypeInfo::DoActionTo(BaseObject *object, const std::string &actionName, const std::vector<Property::Value> &properties)
142 {
143   bool done = false;
144
145   ActionContainer::iterator iter = find_if(mActions.begin(), mActions.end(), PairFinder<std::string, ActionPair>(actionName));
146
147   if( iter != mActions.end() )
148   {
149     done = (iter->second)(object, actionName, properties);
150   }
151   else
152   {
153     DALI_LOG_WARNING("Type '%s' cannot do action '%s'\n", mTypeName.c_str(), actionName.c_str());
154   }
155
156   if(!done)
157   {
158     Dali::TypeInfo base = Dali::TypeRegistry::Get().GetTypeInfo( mBaseTypeName );
159     while( base )
160     {
161       done = GetImplementation(base).DoActionTo(object, actionName, properties);
162       if( done )
163       {
164         break;
165       }
166       base =  Dali::TypeRegistry::Get().GetTypeInfo( base.GetBaseName() );
167     }
168   }
169
170   return done;
171 }
172
173 bool TypeInfo::ConnectSignal( BaseObject* object, ConnectionTrackerInterface* connectionTracker, const std::string& signalName, FunctorDelegate* functor )
174 {
175   bool connected( false );
176
177   ConnectorContainer::iterator iter = find_if( mSignalConnectors.begin(), mSignalConnectors.end(),
178                                                  PairFinder<std::string, ConnectionPair>(signalName) );
179
180   if( iter != mSignalConnectors.end() )
181   {
182     connected = (iter->second)( object, connectionTracker, signalName, functor );
183   }
184
185   return connected;
186 }
187
188 const std::string& TypeInfo::GetName() const
189 {
190   return mTypeName;
191 }
192
193 const std::string& TypeInfo::GetBaseName() const
194 {
195   return mBaseTypeName;
196 }
197
198 Dali::TypeInfo::CreateFunction TypeInfo::GetCreator() const
199 {
200   return mCreate;
201 }
202
203 void TypeInfo::GetActions( Dali::TypeInfo::NameContainer& ret ) const
204 {
205   for(ActionContainer::const_iterator iter = mActions.begin(); iter != mActions.end(); ++iter)
206   {
207     ret.push_back(iter->first);
208   }
209
210   Dali::TypeInfo base = Dali::TypeRegistry::Get().GetTypeInfo( mBaseTypeName );
211   while( base )
212   {
213     for(ActionContainer::const_iterator iter = GetImplementation(base).mActions.begin();
214         iter != GetImplementation(base).mActions.end(); ++iter)
215     {
216       ret.push_back(iter->first);
217     }
218
219     base = Dali::TypeRegistry::Get().GetTypeInfo( base.GetBaseName() );
220   }
221 }
222
223 void TypeInfo::GetSignals(Dali::TypeInfo::NameContainer& ret) const
224 {
225   for(ConnectorContainer::const_iterator iter = mSignalConnectors.begin(); iter != mSignalConnectors.end(); ++iter)
226   {
227     ret.push_back(iter->first);
228   }
229
230   Dali::TypeInfo base = Dali::TypeRegistry::Get().GetTypeInfo( mBaseTypeName );
231   while( base )
232   {
233     for(ConnectorContainer::const_iterator iter = GetImplementation(base).mSignalConnectors.begin();
234         iter != GetImplementation(base).mSignalConnectors.end(); ++iter)
235     {
236       ret.push_back(iter->first);
237     }
238
239     base = Dali::TypeRegistry::Get().GetTypeInfo( base.GetBaseName() );
240   }
241 }
242
243 void TypeInfo::GetProperties( Dali::TypeInfo::NameContainer& ret ) const
244 {
245   Property::IndexContainer indices;
246   GetPropertyIndices(indices);
247
248   ret.reserve(indices.size());
249
250   for(Property::IndexContainer::iterator iter = indices.begin(); iter != indices.end(); ++iter)
251   {
252     const std::string& name = GetPropertyName( *iter );
253     if(name.size())
254     {
255       ret.push_back( name );
256     }
257     else
258     {
259       DALI_LOG_WARNING("Property had no name\n");
260     }
261   }
262 }
263
264 void TypeInfo::GetPropertyIndices( Property::IndexContainer& indices ) const
265 {
266   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
267   if ( base )
268   {
269     const TypeInfo& baseImpl( GetImplementation( base ) );
270     baseImpl.GetPropertyIndices( indices );
271   }
272
273   if ( ! mRegisteredProperties.empty() )
274   {
275     indices.reserve( indices.size() + mRegisteredProperties.size() );
276
277     const RegisteredPropertyContainer::const_iterator endIter = mRegisteredProperties.end();
278     for ( RegisteredPropertyContainer::const_iterator iter = mRegisteredProperties.begin(); iter != endIter; ++iter )
279     {
280       indices.push_back( iter->first );
281     }
282   }
283 }
284
285 const std::string& TypeInfo::GetPropertyName( Property::Index index ) const
286 {
287   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
288                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
289
290   if ( iter != mRegisteredProperties.end() )
291   {
292     return iter->second.name;
293   }
294
295   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
296   if ( base )
297   {
298     return GetImplementation(base).GetPropertyName( index );
299   }
300
301   DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
302 }
303
304 void TypeInfo::AddActionFunction( const std::string &actionName, Dali::TypeInfo::ActionFunction function )
305 {
306   if( NULL == function)
307   {
308     DALI_LOG_WARNING("Action function is empty\n");
309   }
310   else
311   {
312     ActionContainer::iterator iter = std::find_if(mActions.begin(), mActions.end(),
313                                                   PairFinder<std::string, ActionPair>(actionName));
314
315     if( iter == mActions.end() )
316     {
317       mActions.push_back( ActionPair( actionName, function ) );
318     }
319     else
320     {
321       DALI_LOG_WARNING("Action already exists in TypeRegistry Type", actionName.c_str());
322     }
323   }
324 }
325
326 void TypeInfo::AddConnectorFunction( const std::string& signalName, Dali::TypeInfo::SignalConnectorFunction function )
327 {
328   if( NULL == function)
329   {
330     DALI_LOG_WARNING("Connector function is empty\n");
331   }
332   else
333   {
334     ConnectorContainer::iterator iter = find_if( mSignalConnectors.begin(), mSignalConnectors.end(),
335                                                    PairFinder<std::string, ConnectionPair>(signalName) );
336
337     if( iter == mSignalConnectors.end() )
338     {
339       mSignalConnectors.push_back( ConnectionPair( signalName, function ) );
340     }
341     else
342     {
343       DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function", signalName.c_str());
344     }
345   }
346 }
347
348 void TypeInfo::AddProperty( const std::string& name, Property::Index index, Property::Type type, Dali::TypeInfo::SetPropertyFunction setFunc, Dali::TypeInfo::GetPropertyFunction getFunc )
349 {
350   // The setter can be empty as a property can be read-only.
351
352   if ( NULL == getFunc )
353   {
354     DALI_ASSERT_ALWAYS( ! "GetProperty Function is empty" );
355   }
356   else
357   {
358     RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
359                                                           PairFinder< Property::Index, RegisteredPropertyPair>(index) );
360
361     if ( iter == mRegisteredProperties.end() )
362     {
363       mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, setFunc, getFunc, name, Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX ) ) );
364     }
365     else
366     {
367       DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
368     }
369   }
370 }
371
372 void TypeInfo::AddAnimatableProperty( const std::string& name, Property::Index index, Property::Type type )
373 {
374   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
375                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
376
377   if ( iter == mRegisteredProperties.end() )
378   {
379     mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, NULL, NULL, name, Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX ) ) );
380   }
381   else
382   {
383     DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
384   }
385 }
386
387 void TypeInfo::AddAnimatablePropertyComponent( const std::string& name, Property::Index index, Property::Index baseIndex, unsigned int componentIndex )
388 {
389   Property::Type type = GetPropertyType( baseIndex );
390   DALI_ASSERT_ALWAYS( ( type == Property::VECTOR2 || type == Property::VECTOR3 || type == Property::VECTOR4 ) && "Base property does not support component" );
391
392   bool success = false;
393
394   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
395                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
396
397   if ( iter == mRegisteredProperties.end() )
398   {
399     iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
400                     PropertyComponentFinder< RegisteredPropertyPair >( baseIndex, componentIndex ) );
401
402     if ( iter == mRegisteredProperties.end() )
403     {
404       mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, NULL, NULL, name, baseIndex, componentIndex ) ) );
405       success = true;
406     }
407   }
408
409   DALI_ASSERT_ALWAYS( success && "Property component already registered" );
410 }
411
412 unsigned int TypeInfo::GetPropertyCount() const
413 {
414   unsigned int count( mRegisteredProperties.size() );
415
416   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
417   while ( base )
418   {
419     const TypeInfo& baseImpl( GetImplementation(base) );
420     count += baseImpl.mRegisteredProperties.size();
421     base = TypeRegistry::Get()->GetTypeInfo( baseImpl.mBaseTypeName );
422   }
423
424   return count;
425 }
426
427 Property::Index TypeInfo::GetPropertyIndex( const std::string& name ) const
428 {
429   Property::Index index = Property::INVALID_INDEX;
430
431   // Slow but should not be done that often
432   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
433                                                           PropertyNameFinder< RegisteredPropertyPair >( name ) );
434
435   if ( iter != mRegisteredProperties.end() )
436   {
437     index = iter->first;
438   }
439   else
440   {
441     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
442     if ( base )
443     {
444       index = GetImplementation(base).GetPropertyIndex( name );
445     }
446   }
447
448   return index;
449 }
450
451 Property::Index TypeInfo::GetBasePropertyIndex( Property::Index index ) const
452 {
453   Property::Index basePropertyIndex = Property::INVALID_INDEX;
454
455   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
456                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
457
458   if ( iter != mRegisteredProperties.end() )
459   {
460     basePropertyIndex = iter->second.basePropertyIndex;
461   }
462   else
463   {
464     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
465     if ( base )
466     {
467       basePropertyIndex = GetImplementation(base).GetBasePropertyIndex( index );
468     }
469   }
470
471   return basePropertyIndex;
472 }
473
474 int TypeInfo::GetComponentIndex( Property::Index index ) const
475 {
476   int componentIndex = Property::INVALID_COMPONENT_INDEX;
477
478   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
479                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
480
481   if ( iter != mRegisteredProperties.end() )
482   {
483     componentIndex = iter->second.componentIndex;
484   }
485   else
486   {
487     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
488     if ( base )
489     {
490       componentIndex = GetImplementation(base).GetComponentIndex( index );
491     }
492   }
493
494   return componentIndex;
495 }
496
497 bool TypeInfo::IsPropertyWritable( Property::Index index ) const
498 {
499   bool writable( false );
500
501   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
502                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
503
504   if ( iter != mRegisteredProperties.end() )
505   {
506     if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
507     {
508       writable = true; // animatable property is writable
509     }
510     else
511     {
512       writable = iter->second.setFunc ? true : false;
513     }
514   }
515   else
516   {
517     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
518     if ( base )
519     {
520       writable = GetImplementation(base).IsPropertyWritable( index );
521     }
522     else
523     {
524       DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
525     }
526   }
527
528   return writable;
529 }
530
531 Property::Type TypeInfo::GetPropertyType( Property::Index index ) const
532 {
533   Property::Type type( Property::NONE );
534
535   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
536                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
537
538   if ( iter != mRegisteredProperties.end() )
539   {
540     type = iter->second.type;
541   }
542   else
543   {
544     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
545     if ( base )
546     {
547       type = GetImplementation(base).GetPropertyType( index );
548     }
549     else
550     {
551       DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
552     }
553   }
554
555   return type;
556 }
557
558 void TypeInfo::SetProperty( BaseObject *object, Property::Index index, const Property::Value& value ) const
559 {
560   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
561                                                               PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
562   if ( iter != mRegisteredProperties.end() )
563   {
564     if( iter->second.setFunc )
565     {
566       iter->second.setFunc( object, index, value );
567     }
568   }
569   else
570   {
571     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
572     if ( base )
573     {
574       GetImplementation(base).SetProperty( object, index, value );
575     }
576     else
577     {
578       DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
579     }
580   }
581 }
582
583 void TypeInfo::SetProperty( BaseObject *object, const std::string& name, const Property::Value& value ) const
584 {
585   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
586                                                               PropertyNameFinder< RegisteredPropertyPair >( name ) );
587   if ( iter != mRegisteredProperties.end() )
588   {
589     DALI_ASSERT_ALWAYS( iter->second.setFunc && "Trying to write to a read-only property" );
590     iter->second.setFunc( object, iter->first, value );
591   }
592   else
593   {
594     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
595     if ( base )
596     {
597       GetImplementation(base).SetProperty( object, name, value );
598     }
599     else
600     {
601       DALI_ASSERT_ALWAYS( ! "Cannot find property name" );
602     }
603   }
604 }
605
606 Property::Value TypeInfo::GetProperty( const BaseObject *object, Property::Index index ) const
607 {
608   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
609                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
610   if( iter != mRegisteredProperties.end() )
611   {
612     // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
613     return iter->second.getFunc( const_cast< BaseObject* >( object ), index );
614   }
615
616   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
617   if ( base )
618   {
619     return GetImplementation( base ).GetProperty( object, index );
620   }
621
622   DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
623 }
624
625 Property::Value TypeInfo::GetProperty( const BaseObject *object, const std::string& name ) const
626 {
627   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
628                                                           PropertyNameFinder< RegisteredPropertyPair >( name ) );
629   if( iter != mRegisteredProperties.end() )
630   {
631     // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
632     return iter->second.getFunc( const_cast< BaseObject* >( object ), iter->first );
633   }
634
635   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
636   if ( base )
637   {
638     return GetImplementation( base ).GetProperty( object, name );
639   }
640
641   DALI_ASSERT_ALWAYS( ! "Cannot find property name" );
642 }
643
644 } // namespace Internal
645
646 } // namespace Dali