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