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