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