ScrollView - Fix wrapping issue in FixedRuler::GetPageFromPosition
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / builder / replacement.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 // INTERNAL INCLUDES
19 #include <dali-toolkit/internal/builder/replacement.h>
20 #include <dali-toolkit/internal/builder/builder-impl.h>
21 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
22
23 namespace Dali
24 {
25
26 namespace Toolkit
27 {
28
29 namespace Internal
30 {
31
32 namespace  // anon
33 {
34
35 PropertyValueMap::const_iterator FindReplacement( const std::string &str,
36                                                 const PropertyValueMap& overrideMap, const PropertyValueMap& defaultMap )
37 {
38   PropertyValueMap::const_iterator ret  = defaultMap.end();
39
40   PropertyValueMap::const_iterator iter = overrideMap.find( str );
41
42   if( iter != overrideMap.end() )
43   {
44     ret = iter;
45   }
46   else
47   {
48     PropertyValueMap::const_iterator iter = defaultMap.find( str );
49
50     if( iter != defaultMap.end() )
51     {
52       ret = iter;
53     }
54     else
55     {
56       // @ todo
57       // try localized text ie dgettext. Look for colon  {DOMAIN:TEXT} {LC_MESSAGE:ID_XXXX}
58
59     }
60   }
61
62   return ret;
63 }
64
65 std::size_t FirstUnescapedChar(const std::string &initialValue, const std::size_t& startPos, const char c)
66 {
67   std::size_t pos = initialValue.find( c, startPos );
68
69   if(pos > 0)
70   {
71     while( pos != std::string::npos )
72     {
73       if( '\\' == initialValue.at( pos-1 ) )
74       {
75         pos = initialValue.find( c, pos );
76       }
77       else
78       {
79         break;
80       }
81     }
82   }
83
84   return pos;
85 }
86
87 bool GetSubstitutionPosition( const std::string &initialValue, std::size_t &startPos, std::size_t &size )
88 {
89   std::size_t pos = FirstUnescapedChar(initialValue, 0, '{');
90
91   if( std::string::npos == pos )
92   {
93     startPos = std::string::npos;
94     return false;
95   }
96   else
97   {
98     startPos = pos + 1;
99   }
100
101   pos = FirstUnescapedChar(initialValue, startPos, '}');
102
103   if( std::string::npos == pos )
104   {
105     size = std::string::npos;
106     return false;
107   }
108   else
109   {
110     size = pos - startPos;
111   }
112
113   return true;
114 }
115
116 bool ResolvePartialReplacement( const std::string &initialValue, Property::Value &out,
117                                 const PropertyValueMap& overrideMap, const PropertyValueMap& defaultMap )
118 {
119
120   if( initialValue.size() >= 2 )
121   {
122     // eg '{"constants": { "IMAGE_DIR": "/share/images" },
123     //      ...
124     //        "filename":"{IMAGE_DIR}/theme/header.png",
125     //
126     std::size_t startPos = 0;
127     std::size_t size     = std::string::npos;
128
129     if( !GetSubstitutionPosition( initialValue, startPos, size ) )
130     {
131       out = initialValue;
132       return true;
133     }
134     else
135     {
136       const std::string str( initialValue.substr( startPos, size ) );
137
138       PropertyValueMap::const_iterator iter = FindReplacement( str, overrideMap, defaultMap );
139
140       if( iter == defaultMap.end() )
141       {
142         DALI_SCRIPT_WARNING( "Cannot find replacement for '%s'\n", str.c_str() );
143       }
144       else
145       {
146         if( Property::STRING != (*iter).second.GetType() )
147         {
148           DALI_SCRIPT_WARNING( "Cannot replace substring in non string property type='%s'. Initial value '%s'\n",
149                                PropertyTypes::GetName( out.GetType() ), initialValue.c_str() );
150         }
151         else
152         {
153           std::string newString = \
154             initialValue.substr(0, startPos - 1) +
155             (*iter).second.Get<std::string>() +
156             initialValue.substr( startPos + size + 1 );
157
158           return ResolvePartialReplacement( newString, out, overrideMap,  defaultMap );
159         }
160       }
161     }
162   }
163
164   // if we get here we failed
165   return false;
166 }
167
168 } // namespace anon
169
170
171 Replacement::Replacement( const PropertyValueMap& overrideMap, const PropertyValueMap& defaultMap )
172   : mOverrideMap( &overrideMap ), mDefaultMap( &defaultMap )
173 {
174
175 }
176
177 namespace
178 {
179 PropertyValueMap noMap;
180 }
181
182 Replacement::Replacement( const PropertyValueMap& defaultMap )
183   : mOverrideMap( &noMap ), mDefaultMap( &defaultMap )
184 {
185
186 }
187
188 Replacement::Replacement(  )
189   : mOverrideMap( &noMap ), mDefaultMap( &noMap )
190 {
191
192 }
193
194 OptionalString Replacement::HasFullReplacement( const TreeNode & node ) const
195 {
196   OptionalString ret;
197
198   if( node.HasSubstitution() && ((*mOverrideMap).size() || (*mDefaultMap).size()) )
199   {
200     OptionalString v = ::IsString( node );
201     if( v )
202     {
203       const std::string& initialValue = *v;
204       if( (initialValue[ 0 ] == '{') && (initialValue[ initialValue.size() -1 ] == '}') )
205       {
206         ret = initialValue.substr( 1, initialValue.size() - 2 );
207       }
208     }
209   }
210   return ret;
211 }
212
213 Property::Value Replacement::GetFullReplacement( const std::string& replacementString ) const
214 {
215   Property::Value out;
216   DALI_ASSERT_DEBUG( mOverrideMap && "missing map");
217   DALI_ASSERT_DEBUG( mDefaultMap && "missing map");
218
219   PropertyValueMap::const_iterator iter = FindReplacement( replacementString, *mOverrideMap, *mDefaultMap );
220
221   if( iter == (*mDefaultMap).end() )
222   {
223     DALI_SCRIPT_WARNING("Cannot find replacement for '%s'\n", replacementString.c_str());
224   }
225   else
226   {
227     out = (*iter).second;
228 #if defined(DEBUG_ENABLED)
229     DALI_SCRIPT_VERBOSE("  Full replacement for '%s' => to Type '%s'\n",
230                         replacementString.c_str(),
231                         PropertyTypes::GetName( out.GetType()) );
232 #endif
233   }
234
235   return out;
236 }
237
238 OptionalBoolean Replacement::IsBoolean( const TreeNode & node ) const
239 {
240   OptionalBoolean ret;
241   if( OptionalString replace = HasFullReplacement( node ) )
242   {
243     Property::Value value = GetFullReplacement( *replace );
244     if( Property::BOOLEAN == value.GetType() )
245     {
246       ret = value.Get<bool>();
247     }
248   }
249   else
250   {
251     ret = ::IsBoolean( node );
252   }
253   return ret;
254 }
255
256 OptionalBoolean Replacement::IsBoolean( OptionalChild child ) const
257 {
258   if( child )
259   {
260     return IsBoolean( *child );
261   }
262   else
263   {
264     return OptionalBoolean();
265   }
266 }
267
268 // template <typename T, OptionalValue<T> (*ISTYPE)( const TreeNode& node ), Property::Type TYPE>
269 // OptionalValue<T> IsOfType( const TreeNode& node, const PropertyValueMap& overrideMap, const PropertyValueMap& defaultMap )
270 // {
271 //   OptionalValue<T> ret;
272 //   if( OptionalString replace = HasFullReplacement( node, overrideMap, defaultMap ) )
273 //   {
274 //     Property::Value value = GetFullReplacement( *replace, overrideMap, defaultMap );
275 //     if( TYPE == value.GetType() )
276 //     {
277 //       ret = value.Get<T>();
278 //     }
279 //   }
280 //   else
281 //   {
282 //     ret = ISTYPE( node );
283 //   }
284 //   return ret;
285
286 // }
287
288 // OptionalFloat Replacement::IsFloat( const TreeNode & node ) const
289 // {
290 //   return IsOfType<float, ::IsFloat, Property::FLOAT>( node, *mOverrideMap, *mDefaultMap );
291 //   /* OptionalFloat ret; */
292 //   /* if( OptionalString replace = HasFullReplacement( node ) ) */
293 //   /* { */
294 //   /*   Property::Value value = GetFullReplacement( replace ); */
295 //   /*   if( Property::FLOAT == value.GetType() ) */
296 //   /*   { */
297 //   /*     ret = value.Get<float>(); */
298 //   /*   } */
299 //   /* } */
300 //   /* else */
301 //   /* { */
302 //   /*   ret = IsFloat( node ); */
303 //   /* } */
304 //   /* return ret; */
305 // }
306
307 OptionalFloat Replacement::IsFloat( const TreeNode & node ) const
308 {
309   OptionalFloat ret;
310   if( OptionalString replace = HasFullReplacement( node ) )
311   {
312     Property::Value value = GetFullReplacement( *replace );
313     if( Property::FLOAT == value.GetType() )
314     {
315       ret = value.Get<float>();
316     }
317   }
318   else
319   {
320     ret = ::IsFloat( node );
321   }
322   return ret;
323 }
324
325 OptionalString Replacement::IsString( const TreeNode& node ) const
326 {
327   OptionalString ret;
328
329   DALI_ASSERT_DEBUG( mOverrideMap && "missing map");
330   DALI_ASSERT_DEBUG( mDefaultMap && "missing map");
331
332   if( node.HasSubstitution() && ((*mOverrideMap).size() || (*mDefaultMap).size()) )
333   {
334     if( OptionalString v = ::IsString( node ) )
335     {
336       Property::Value value;
337       if( ResolvePartialReplacement( *v, value, *mOverrideMap, *mDefaultMap ) )
338       {
339         if( Property::STRING == value.GetType() )
340         {
341           ret = value.Get<std::string>();
342 #if defined(DEBUG_ENABLED)
343           DALI_SCRIPT_VERBOSE("  Resolved substring replacement for '%s' => '%s'\n", (*v).c_str(), (*ret).c_str());
344 #endif
345         }
346       }
347       else
348       {
349         if( Property::STRING == value.GetType() )
350         {
351           ret = v; // sets the unexpanded. Expansion may occur later in processing with include files
352         }
353       }
354     }
355   }
356   else
357   {
358     ret = ::IsString( node );
359   }
360   return ret;
361 }
362
363 OptionalInteger Replacement::IsInteger( const TreeNode & node ) const
364 {
365   OptionalInteger ret;
366   if( OptionalString replace = HasFullReplacement( node ) )
367   {
368     Property::Value value = GetFullReplacement( *replace );
369     if( Property::INTEGER == value.GetType() )
370     {
371       ret = value.Get<int>();
372     }
373   }
374   else
375   {
376     ret = ::IsInteger( node );
377   }
378   return ret;
379 }
380
381 OptionalUnsignedInt Replacement::IsUnsignedInteger( const TreeNode & node ) const
382 {
383   OptionalUnsignedInt ret;
384   if( OptionalString replace = HasFullReplacement( node ) )
385   {
386     Property::Value value = GetFullReplacement( *replace );
387     if( Property::UNSIGNED_INTEGER == value.GetType() )
388     {
389       ret = value.Get<unsigned int>();
390     }
391   }
392   else
393   {
394     if ( OptionalInteger i = ::IsInteger( node ) )
395     {
396       ret = OptionalUnsignedInt(static_cast<unsigned int>(*i) );
397     }
398   }
399   return ret;
400 }
401
402 OptionalVector2 Replacement::IsVector2( const TreeNode & node ) const
403 {
404   OptionalVector2 ret;
405   if( OptionalString replace = HasFullReplacement( node ) )
406   {
407     Property::Value value = GetFullReplacement( *replace );
408     if( Property::VECTOR2 == value.GetType() )
409     {
410       ret = value.Get<Vector2>();
411     }
412   }
413   else
414   {
415     ret = ::IsVector2( node );
416   }
417   return ret;
418 }
419
420 OptionalVector3 Replacement::IsVector3( const TreeNode & node ) const
421 {
422   OptionalVector3 ret;
423   if( OptionalString replace = HasFullReplacement( node ) )
424   {
425     Property::Value value = GetFullReplacement( *replace );
426     if( Property::VECTOR3 == value.GetType() )
427     {
428       ret = value.Get<Vector3>();
429     }
430   }
431   else
432   {
433     ret = ::IsVector3( node );
434   }
435   return ret;
436 }
437
438 OptionalVector4 Replacement::IsVector4( const TreeNode & node ) const
439 {
440   OptionalVector4 ret;
441   if( OptionalString replace = HasFullReplacement( node ) )
442   {
443     Property::Value value = GetFullReplacement( *replace );
444     if( Property::VECTOR4 == value.GetType() )
445     {
446       ret = value.Get<Vector4>();
447     }
448   }
449   else
450   {
451     ret = ::IsVector4( node );
452   }
453   return ret;
454 }
455
456 OptionalMatrix Replacement::IsMatrix( const TreeNode & node ) const
457 {
458   OptionalMatrix ret;
459   if( OptionalString replace = HasFullReplacement( node ) )
460   {
461     Property::Value value = GetFullReplacement( *replace );
462     if( Property::MATRIX == value.GetType() )
463     {
464       ret = value.Get<Matrix>();
465     }
466   }
467   else
468   {
469     ret = ::IsMatrix( node );
470   }
471   return ret;
472 }
473
474 OptionalMatrix3 Replacement::IsMatrix3( const TreeNode & node ) const
475 {
476   OptionalMatrix3 ret;
477   if( OptionalString replace = HasFullReplacement( node ) )
478   {
479     Property::Value value = GetFullReplacement( *replace );
480     if( Property::MATRIX3 == value.GetType() )
481     {
482       ret = value.Get<Matrix3>();
483     }
484   }
485   else
486   {
487     ret = ::IsMatrix3( node );
488   }
489   return ret;
490 }
491
492 OptionalRect Replacement::IsRect( const TreeNode & node ) const
493 {
494   OptionalRect ret;
495   if( OptionalString replace = HasFullReplacement( node ) )
496   {
497     Property::Value value = GetFullReplacement( *replace );
498     if( Property::RECTANGLE == value.GetType() )
499     {
500       ret = value.Get<Rect<int> >();
501     }
502   }
503   else
504   {
505     ret = ::IsRect( node );
506   }
507   return ret;
508 }
509
510
511
512 OptionalFloat Replacement::IsFloat( OptionalChild child ) const
513 {
514   if( child )
515   {
516     return IsFloat( *child );
517   }
518   else
519   {
520     return OptionalFloat();
521   }
522 }
523
524
525 OptionalString Replacement::IsString( OptionalChild child ) const
526 {
527   if( child )
528   {
529     return IsString( *child );
530   }
531   else
532   {
533     return OptionalString();
534   }
535 }
536
537 OptionalInteger Replacement::IsInteger( OptionalChild child ) const
538 {
539   if( child )
540   {
541     return IsInteger( *child );
542   }
543   else
544   {
545     return OptionalInteger();
546   }
547 }
548
549 OptionalVector2 Replacement::IsVector2( OptionalChild child ) const
550 {
551   if( child )
552   {
553     return IsVector2( *child );
554   }
555   else
556   {
557     return OptionalVector2();
558   }
559 }
560
561 OptionalVector3 Replacement::IsVector3( OptionalChild child ) const
562 {
563   if( child )
564   {
565     return IsVector3( *child );
566   }
567   else
568   {
569     return OptionalVector3();
570   }
571 }
572
573 OptionalVector4 Replacement::IsVector4( OptionalChild child ) const
574 {
575   if( child )
576   {
577     return IsVector4( *child );
578   }
579   else
580   {
581     return OptionalVector4();
582   }
583 }
584
585 OptionalMatrix Replacement::IsMatrix( OptionalChild child ) const
586 {
587   if( child )
588   {
589     return IsMatrix( *child );
590   }
591   else
592   {
593     return OptionalMatrix();
594   }
595 }
596
597 OptionalMatrix3 Replacement::IsMatrix3( OptionalChild child ) const
598 {
599   if( child )
600   {
601     return IsMatrix3( *child );
602   }
603   else
604   {
605     return OptionalMatrix3();
606   }
607 }
608
609 OptionalRect Replacement::IsRect( OptionalChild child ) const
610 {
611   if( child )
612   {
613     return IsRect( *child );
614   }
615   else
616   {
617     return OptionalRect();
618   }
619 }
620
621 bool Replacement::IsMap( OptionalChild child, Property::Value& out ) const
622 {
623   bool ret = false;
624
625   if( child )
626   {
627     if( OptionalString replace = HasFullReplacement( *child ) )
628     {
629       out = GetFullReplacement( *replace );
630       if( Property::MAP == out.GetType() )
631       {
632         ret = true;
633       }
634     }
635   }
636
637   return ret;
638 }
639
640 bool Replacement::IsArray( OptionalChild child, Property::Value& out ) const
641 {
642   bool ret = false;
643
644   if( child )
645   {
646     if( OptionalString replace = HasFullReplacement( *child ) )
647     {
648       out = GetFullReplacement( *replace );
649       if( Property::ARRAY == out.GetType() )
650       {
651         ret = true;
652       }
653     }
654   }
655
656   return ret;
657 }
658
659 } // namespace Internal
660
661 } // namespace Toolkit
662
663 } // namespace Dali
664