UTC missing tests for TypeInfo & NativeImageInterface
[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 Property::Map &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 size_t TypeInfo::GetActionCount() const
204 {
205   size_t count = mActions.size();
206
207   Dali::TypeInfo base = Dali::TypeRegistry::Get().GetTypeInfo( mBaseTypeName );
208   while( base )
209   {
210     count += GetImplementation(base).mActions.size();
211     base = Dali::TypeRegistry::Get().GetTypeInfo( base.GetBaseName() );
212   }
213
214   return count;
215 }
216
217 std::string TypeInfo::GetActionName(size_t index) const
218 {
219   std::string name;
220
221   if( index < mActions.size() )
222   {
223     name = mActions[index].first;
224   }
225   else
226   {
227     size_t count = mActions.size();
228
229     Dali::TypeInfo base = Dali::TypeRegistry::Get().GetTypeInfo( mBaseTypeName );
230     while( base )
231     {
232       size_t baseCount = GetImplementation(base).mActions.size();
233
234       if( index < count + baseCount )
235       {
236         name = GetImplementation(base).mActions[ index - count ].first;
237         break;
238       }
239
240       count += baseCount;
241
242       base = Dali::TypeRegistry::Get().GetTypeInfo( base.GetBaseName() );
243     }
244   }
245
246   return name;
247 }
248
249 size_t TypeInfo::GetSignalCount() const
250 {
251   size_t count = mSignalConnectors.size();
252
253   Dali::TypeInfo base = Dali::TypeRegistry::Get().GetTypeInfo( mBaseTypeName );
254   while( base )
255   {
256     count += GetImplementation(base).mSignalConnectors.size();
257     base = Dali::TypeRegistry::Get().GetTypeInfo( base.GetBaseName() );
258   }
259
260   return count;
261 }
262
263 std::string TypeInfo::GetSignalName(size_t index) const
264 {
265   std::string name;
266
267   if( index < mSignalConnectors.size() )
268   {
269     name = mSignalConnectors[index].first;
270   }
271   else
272   {
273     size_t count = mSignalConnectors.size();
274
275     Dali::TypeInfo base = Dali::TypeRegistry::Get().GetTypeInfo( mBaseTypeName );
276     while( base )
277     {
278       size_t baseCount = GetImplementation(base).mSignalConnectors.size();
279
280       if( index < count + baseCount )
281       {
282         name = GetImplementation(base).mSignalConnectors[ index - count ].first;
283         break;
284       }
285
286       count += baseCount;
287
288       base = Dali::TypeRegistry::Get().GetTypeInfo( base.GetBaseName() );
289     }
290   }
291
292   return name;
293 }
294
295 void TypeInfo::GetPropertyIndices( Property::IndexContainer& indices ) const
296 {
297   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
298   if ( base )
299   {
300     const TypeInfo& baseImpl( GetImplementation( base ) );
301     baseImpl.GetPropertyIndices( indices );
302   }
303
304   if ( ! mRegisteredProperties.empty() )
305   {
306     indices.Reserve( indices.Size() + mRegisteredProperties.size() );
307
308     const RegisteredPropertyContainer::const_iterator endIter = mRegisteredProperties.end();
309     for ( RegisteredPropertyContainer::const_iterator iter = mRegisteredProperties.begin(); iter != endIter; ++iter )
310     {
311       indices.PushBack( iter->first );
312     }
313   }
314 }
315
316 const std::string& TypeInfo::GetPropertyName( Property::Index index ) const
317 {
318   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
319                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
320
321   if ( iter != mRegisteredProperties.end() )
322   {
323     return iter->second.name;
324   }
325
326   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
327   if ( base )
328   {
329     return GetImplementation(base).GetPropertyName( index );
330   }
331
332   DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
333 }
334
335 void TypeInfo::AddActionFunction( const std::string &actionName, Dali::TypeInfo::ActionFunction function )
336 {
337   if( NULL == function)
338   {
339     DALI_LOG_WARNING("Action function is empty\n");
340   }
341   else
342   {
343     ActionContainer::iterator iter = std::find_if(mActions.begin(), mActions.end(),
344                                                   PairFinder<std::string, ActionPair>(actionName));
345
346     if( iter == mActions.end() )
347     {
348       mActions.push_back( ActionPair( actionName, function ) );
349     }
350     else
351     {
352       DALI_LOG_WARNING("Action already exists in TypeRegistry Type", actionName.c_str());
353     }
354   }
355 }
356
357 void TypeInfo::AddConnectorFunction( const std::string& signalName, Dali::TypeInfo::SignalConnectorFunction function )
358 {
359   if( NULL == function)
360   {
361     DALI_LOG_WARNING("Connector function is empty\n");
362   }
363   else
364   {
365     ConnectorContainer::iterator iter = find_if( mSignalConnectors.begin(), mSignalConnectors.end(),
366                                                    PairFinder<std::string, ConnectionPair>(signalName) );
367
368     if( iter == mSignalConnectors.end() )
369     {
370       mSignalConnectors.push_back( ConnectionPair( signalName, function ) );
371     }
372     else
373     {
374       DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function", signalName.c_str());
375     }
376   }
377 }
378
379 void TypeInfo::AddProperty( const std::string& name, Property::Index index, Property::Type type, Dali::TypeInfo::SetPropertyFunction setFunc, Dali::TypeInfo::GetPropertyFunction getFunc )
380 {
381   // The setter can be empty as a property can be read-only.
382
383   if ( NULL == getFunc )
384   {
385     DALI_ASSERT_ALWAYS( ! "GetProperty Function is empty" );
386   }
387   else
388   {
389     RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
390                                                           PairFinder< Property::Index, RegisteredPropertyPair>(index) );
391
392     if ( iter == mRegisteredProperties.end() )
393     {
394       mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, setFunc, getFunc, name, Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX ) ) );
395     }
396     else
397     {
398       DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
399     }
400   }
401 }
402
403 void TypeInfo::AddAnimatableProperty( const std::string& name, Property::Index index, Property::Type type )
404 {
405   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
406                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
407
408   if ( iter == mRegisteredProperties.end() )
409   {
410     mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, NULL, NULL, name, Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX ) ) );
411   }
412   else
413   {
414     DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
415   }
416 }
417
418 void TypeInfo::AddAnimatablePropertyComponent( const std::string& name, Property::Index index, Property::Index baseIndex, unsigned int componentIndex )
419 {
420   Property::Type type = GetPropertyType( baseIndex );
421   DALI_ASSERT_ALWAYS( ( type == Property::VECTOR2 || type == Property::VECTOR3 || type == Property::VECTOR4 ) && "Base property does not support component" );
422
423   bool success = false;
424
425   RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
426                                                         PairFinder< Property::Index, RegisteredPropertyPair>(index) );
427
428   if ( iter == mRegisteredProperties.end() )
429   {
430     iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
431                     PropertyComponentFinder< RegisteredPropertyPair >( baseIndex, componentIndex ) );
432
433     if ( iter == mRegisteredProperties.end() )
434     {
435       mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, NULL, NULL, name, baseIndex, componentIndex ) ) );
436       success = true;
437     }
438   }
439
440   DALI_ASSERT_ALWAYS( success && "Property component already registered" );
441 }
442
443 size_t TypeInfo::GetPropertyCount() const
444 {
445   size_t count( mRegisteredProperties.size() );
446
447   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
448   while ( base )
449   {
450     const TypeInfo& baseImpl( GetImplementation(base) );
451     count += baseImpl.mRegisteredProperties.size();
452     base = TypeRegistry::Get()->GetTypeInfo( baseImpl.mBaseTypeName );
453   }
454
455   return count;
456 }
457
458 Property::Index TypeInfo::GetPropertyIndex( const std::string& name ) const
459 {
460   Property::Index index = Property::INVALID_INDEX;
461
462   // Slow but should not be done that often
463   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
464                                                           PropertyNameFinder< RegisteredPropertyPair >( name ) );
465
466   if ( iter != mRegisteredProperties.end() )
467   {
468     index = iter->first;
469   }
470   else
471   {
472     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
473     if ( base )
474     {
475       index = GetImplementation(base).GetPropertyIndex( name );
476     }
477   }
478
479   return index;
480 }
481
482 Property::Index TypeInfo::GetBasePropertyIndex( Property::Index index ) const
483 {
484   Property::Index basePropertyIndex = Property::INVALID_INDEX;
485
486   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
487                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
488
489   if ( iter != mRegisteredProperties.end() )
490   {
491     basePropertyIndex = iter->second.basePropertyIndex;
492   }
493   else
494   {
495     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
496     if ( base )
497     {
498       basePropertyIndex = GetImplementation(base).GetBasePropertyIndex( index );
499     }
500   }
501
502   return basePropertyIndex;
503 }
504
505 int TypeInfo::GetComponentIndex( Property::Index index ) const
506 {
507   int componentIndex = Property::INVALID_COMPONENT_INDEX;
508
509   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
510                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
511
512   if ( iter != mRegisteredProperties.end() )
513   {
514     componentIndex = iter->second.componentIndex;
515   }
516   else
517   {
518     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
519     if ( base )
520     {
521       componentIndex = GetImplementation(base).GetComponentIndex( index );
522     }
523   }
524
525   return componentIndex;
526 }
527
528 bool TypeInfo::IsPropertyWritable( Property::Index index ) const
529 {
530   bool writable( false );
531
532   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
533                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
534
535   if ( iter != mRegisteredProperties.end() )
536   {
537     if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
538     {
539       writable = true; // animatable property is writable
540     }
541     else
542     {
543       writable = iter->second.setFunc ? true : false;
544     }
545   }
546   else
547   {
548     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
549     if ( base )
550     {
551       writable = GetImplementation(base).IsPropertyWritable( index );
552     }
553     else
554     {
555       DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
556     }
557   }
558
559   return writable;
560 }
561
562 Property::Type TypeInfo::GetPropertyType( Property::Index index ) const
563 {
564   Property::Type type( Property::NONE );
565
566   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
567                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
568
569   if ( iter != mRegisteredProperties.end() )
570   {
571     type = iter->second.type;
572   }
573   else
574   {
575     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
576     if ( base )
577     {
578       type = GetImplementation(base).GetPropertyType( index );
579     }
580     else
581     {
582       DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
583     }
584   }
585
586   return type;
587 }
588
589 void TypeInfo::SetProperty( BaseObject *object, Property::Index index, const Property::Value& value ) const
590 {
591   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
592                                                               PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
593   if ( iter != mRegisteredProperties.end() )
594   {
595     if( iter->second.setFunc )
596     {
597       iter->second.setFunc( object, index, value );
598     }
599   }
600   else
601   {
602     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
603     if ( base )
604     {
605       GetImplementation(base).SetProperty( object, index, value );
606     }
607     else
608     {
609       DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
610     }
611   }
612 }
613
614 void TypeInfo::SetProperty( BaseObject *object, const std::string& name, const Property::Value& value ) const
615 {
616   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
617                                                               PropertyNameFinder< RegisteredPropertyPair >( name ) );
618   if ( iter != mRegisteredProperties.end() )
619   {
620     DALI_ASSERT_ALWAYS( iter->second.setFunc && "Trying to write to a read-only property" );
621     iter->second.setFunc( object, iter->first, value );
622   }
623   else
624   {
625     Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
626     if ( base )
627     {
628       GetImplementation(base).SetProperty( object, name, value );
629     }
630     else
631     {
632       DALI_ASSERT_ALWAYS( ! "Cannot find property name" );
633     }
634   }
635 }
636
637 Property::Value TypeInfo::GetProperty( const BaseObject *object, Property::Index index ) const
638 {
639   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
640                                                           PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
641   if( iter != mRegisteredProperties.end() )
642   {
643     // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
644     return iter->second.getFunc( const_cast< BaseObject* >( object ), index );
645   }
646
647   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
648   if ( base )
649   {
650     return GetImplementation( base ).GetProperty( object, index );
651   }
652
653   DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
654 }
655
656 Property::Value TypeInfo::GetProperty( const BaseObject *object, const std::string& name ) const
657 {
658   RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
659                                                           PropertyNameFinder< RegisteredPropertyPair >( name ) );
660   if( iter != mRegisteredProperties.end() )
661   {
662     // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
663     return iter->second.getFunc( const_cast< BaseObject* >( object ), iter->first );
664   }
665
666   Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
667   if ( base )
668   {
669     return GetImplementation( base ).GetProperty( object, name );
670   }
671
672   DALI_ASSERT_ALWAYS( ! "Cannot find property name" );
673 }
674
675 } // namespace Internal
676
677 } // namespace Dali