701b7c8e6faccb2341d18a52964bf35b916e3dd2
[platform/core/uifw/dali-toolkit.git] / 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     }
347   }
348   else
349   {
350     ret = ::IsString( node );
351   }
352   return ret;
353 }
354
355 OptionalInteger Replacement::IsInteger( const TreeNode & node ) const
356 {
357   OptionalInteger ret;
358   if( OptionalString replace = HasFullReplacement( node ) )
359   {
360     Property::Value value = GetFullReplacement( *replace );
361     if( Property::INTEGER == value.GetType() )
362     {
363       ret = value.Get<int>();
364     }
365   }
366   else
367   {
368     ret = ::IsInteger( node );
369   }
370   return ret;
371 }
372
373 OptionalVector2 Replacement::IsVector2( const TreeNode & node ) const
374 {
375   OptionalVector2 ret;
376   if( OptionalString replace = HasFullReplacement( node ) )
377   {
378     Property::Value value = GetFullReplacement( *replace );
379     if( Property::VECTOR2 == value.GetType() )
380     {
381       ret = value.Get<Vector2>();
382     }
383   }
384   else
385   {
386     ret = ::IsVector2( node );
387   }
388   return ret;
389 }
390
391 OptionalVector3 Replacement::IsVector3( const TreeNode & node ) const
392 {
393   OptionalVector3 ret;
394   if( OptionalString replace = HasFullReplacement( node ) )
395   {
396     Property::Value value = GetFullReplacement( *replace );
397     if( Property::VECTOR3 == value.GetType() )
398     {
399       ret = value.Get<Vector3>();
400     }
401   }
402   else
403   {
404     ret = ::IsVector3( node );
405   }
406   return ret;
407 }
408
409 OptionalVector4 Replacement::IsVector4( const TreeNode & node ) const
410 {
411   OptionalVector4 ret;
412   if( OptionalString replace = HasFullReplacement( node ) )
413   {
414     Property::Value value = GetFullReplacement( *replace );
415     if( Property::VECTOR4 == value.GetType() )
416     {
417       ret = value.Get<Vector4>();
418     }
419   }
420   else
421   {
422     ret = ::IsVector4( node );
423   }
424   return ret;
425 }
426
427 OptionalMatrix Replacement::IsMatrix( const TreeNode & node ) const
428 {
429   OptionalMatrix ret;
430   if( OptionalString replace = HasFullReplacement( node ) )
431   {
432     Property::Value value = GetFullReplacement( *replace );
433     if( Property::MATRIX == value.GetType() )
434     {
435       ret = value.Get<Matrix>();
436     }
437   }
438   else
439   {
440     ret = ::IsMatrix( node );
441   }
442   return ret;
443 }
444
445 OptionalMatrix3 Replacement::IsMatrix3( const TreeNode & node ) const
446 {
447   OptionalMatrix3 ret;
448   if( OptionalString replace = HasFullReplacement( node ) )
449   {
450     Property::Value value = GetFullReplacement( *replace );
451     if( Property::MATRIX3 == value.GetType() )
452     {
453       ret = value.Get<Matrix3>();
454     }
455   }
456   else
457   {
458     ret = ::IsMatrix3( node );
459   }
460   return ret;
461 }
462
463 OptionalRect Replacement::IsRect( const TreeNode & node ) const
464 {
465   OptionalRect ret;
466   if( OptionalString replace = HasFullReplacement( node ) )
467   {
468     Property::Value value = GetFullReplacement( *replace );
469     if( Property::RECTANGLE == value.GetType() )
470     {
471       ret = value.Get<Rect<int> >();
472     }
473   }
474   else
475   {
476     ret = ::IsRect( node );
477   }
478   return ret;
479 }
480
481
482
483 OptionalFloat Replacement::IsFloat( OptionalChild child ) const
484 {
485   if( child )
486   {
487     return IsFloat( *child );
488   }
489   else
490   {
491     return OptionalFloat();
492   }
493 }
494
495
496 OptionalString Replacement::IsString( OptionalChild child ) const
497 {
498   if( child )
499   {
500     return IsString( *child );
501   }
502   else
503   {
504     return OptionalString();
505   }
506 }
507
508 OptionalInteger Replacement::IsInteger( OptionalChild child ) const
509 {
510   if( child )
511   {
512     return IsInteger( *child );
513   }
514   else
515   {
516     return OptionalInteger();
517   }
518 }
519
520 OptionalVector2 Replacement::IsVector2( OptionalChild child ) const
521 {
522   if( child )
523   {
524     return IsVector2( *child );
525   }
526   else
527   {
528     return OptionalVector2();
529   }
530 }
531
532 OptionalVector3 Replacement::IsVector3( OptionalChild child ) const
533 {
534   if( child )
535   {
536     return IsVector3( *child );
537   }
538   else
539   {
540     return OptionalVector3();
541   }
542 }
543
544 OptionalVector4 Replacement::IsVector4( OptionalChild child ) const
545 {
546   if( child )
547   {
548     return IsVector4( *child );
549   }
550   else
551   {
552     return OptionalVector4();
553   }
554 }
555
556 OptionalMatrix Replacement::IsMatrix( OptionalChild child ) const
557 {
558   if( child )
559   {
560     return IsMatrix( *child );
561   }
562   else
563   {
564     return OptionalMatrix();
565   }
566 }
567
568 OptionalMatrix3 Replacement::IsMatrix3( OptionalChild child ) const
569 {
570   if( child )
571   {
572     return IsMatrix3( *child );
573   }
574   else
575   {
576     return OptionalMatrix3();
577   }
578 }
579
580 OptionalRect Replacement::IsRect( OptionalChild child ) const
581 {
582   if( child )
583   {
584     return IsRect( *child );
585   }
586   else
587   {
588     return OptionalRect();
589   }
590 }
591
592 bool Replacement::IsMap( OptionalChild child, Property::Value& out ) const
593 {
594   bool ret = false;
595
596   if( child )
597   {
598     if( OptionalString replace = HasFullReplacement( *child ) )
599     {
600       out = GetFullReplacement( *replace );
601       if( Property::MAP == out.GetType() )
602       {
603         ret = true;
604       }
605     }
606   }
607
608   return ret;
609 }
610
611 bool Replacement::IsArray( OptionalChild child, Property::Value& out ) const
612 {
613   bool ret = false;
614
615   if( child )
616   {
617     if( OptionalString replace = HasFullReplacement( *child ) )
618     {
619       out = GetFullReplacement( *replace );
620       if( Property::ARRAY == out.GetType() )
621       {
622         ret = true;
623       }
624     }
625   }
626
627   return ret;
628 }
629
630 } // namespace Internal
631
632 } // namespace Toolkit
633
634 } // namespace Dali
635