Replace std::string global variables with C-style string.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / builder / builder-impl.cpp
1 /*
2  * Copyright (c) 2022 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 // CLASS HEADER
19 #include <dali-toolkit/internal/builder/builder-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <sys/stat.h>
23 #include <sstream>
24
25 #include <dali-toolkit/devel-api/controls/control-devel.h>
26 #include <dali/devel-api/common/stage.h>
27 #include <dali/devel-api/scripting/scripting.h>
28 #include <dali/integration-api/debug.h>
29 #include <dali/public-api/actors/camera-actor.h>
30 #include <dali/public-api/actors/layer.h>
31 #include <dali/public-api/object/property-array.h>
32 #include <dali/public-api/object/type-info.h>
33 #include <dali/public-api/object/type-registry.h>
34 #include <dali/public-api/render-tasks/render-task-list.h>
35 #include <dali/public-api/rendering/shader.h>
36 #include <dali/public-api/signals/functor-delegate.h>
37
38 // INTERNAL INCLUDES
39 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
40 #include <dali-toolkit/devel-api/builder/json-parser.h>
41 #include <dali-toolkit/public-api/controls/control.h>
42
43 #include <dali-toolkit/internal/builder/builder-declarations.h>
44 #include <dali-toolkit/internal/builder/builder-filesystem.h>
45 #include <dali-toolkit/internal/builder/builder-get-is.inl.h>
46 #include <dali-toolkit/internal/builder/builder-impl-debug.h>
47 #include <dali-toolkit/internal/builder/builder-set-property.h>
48 #include <dali-toolkit/internal/builder/replacement.h>
49 #include <dali-toolkit/internal/builder/tree-node-manipulator.h>
50
51 namespace Dali
52 {
53 namespace Toolkit
54 {
55 namespace Internal
56 {
57 class Replacement;
58
59 extern Animation CreateAnimation(const TreeNode& child, const Replacement& replacements, const Dali::Actor searchRoot, Builder* const builder);
60
61 extern Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode& root, const TreeNode& child, Actor actor, Dali::Toolkit::Internal::Builder* const builder);
62
63 extern Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode& root, const TreeNode& child, Actor actor, Dali::Toolkit::Internal::Builder* const builder);
64
65 #if defined(DEBUG_ENABLED)
66 Integration::Log::Filter* gFilterScript = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_SCRIPT");
67 #endif
68
69 namespace
70 {
71 #define TOKEN_STRING(x) #x
72
73 const char* KEYNAME_ACTORS           = "actors";
74 const char* KEYNAME_ENTRY_TRANSITION = "entryTransition";
75 const char* KEYNAME_EXIT_TRANSITION  = "exitTransition";
76 const char* KEYNAME_INCLUDES         = "includes";
77 const char* KEYNAME_INHERIT          = "inherit";
78 const char* KEYNAME_MAPPINGS         = "mappings";
79 const char* KEYNAME_SIGNALS          = "signals";
80 const char* KEYNAME_STATES           = "states";
81 const char* KEYNAME_STYLES           = "styles";
82 const char* KEYNAME_TEMPLATES        = "templates";
83 const char* KEYNAME_TRANSITIONS      = "transitions";
84 const char* KEYNAME_TYPE             = "type";
85 const char* KEYNAME_VISUALS          = "visuals";
86
87 const char* PROPERTIES            = "properties";
88 const char* ANIMATABLE_PROPERTIES = "animatableProperties";
89
90 typedef std::vector<const TreeNode*> TreeNodeList;
91
92 bool GetMappingKey(const std::string& str, std::string& key)
93 {
94   bool        result = false;
95   std::string test(str);
96   if(!test.empty())
97   {
98     if(test.at(0) == '<')
99     {
100       if(test.at(test.length() - 1) == '>')
101       {
102         key    = test.substr(1, test.length() - 2);
103         result = true;
104       }
105     }
106   }
107   return result;
108 }
109
110 /*
111  * Recursively collects all styles in a node (An array of style names).
112  *
113  * stylesCollection The set of styles from the json file (a json object of named styles)
114  * style The style array to begin the collection from
115  * styleList The style list to add nodes to apply
116  */
117 void CollectAllStyles(const TreeNode& stylesCollection, const TreeNode& style, TreeNodeList& styleList)
118 {
119   // style is an array of style names
120   if(TreeNode::ARRAY == style.GetType())
121   {
122     for(TreeNode::ConstIterator iter = style.CBegin(); iter != style.CEnd(); ++iter)
123     {
124       if(OptionalString styleName = IsString((*iter).second))
125       {
126         if(OptionalChild node = IsChildIgnoreCase(stylesCollection, *styleName))
127         {
128           styleList.push_back(&(*node));
129
130           OptionalChild subStyle = IsChild(*node, KEYNAME_INHERIT);
131           if(!subStyle)
132           {
133             subStyle = IsChild(*node, KEYNAME_STYLES);
134           }
135           if(subStyle)
136           {
137             CollectAllStyles(stylesCollection, *subStyle, styleList);
138           }
139         }
140       }
141     }
142   }
143 }
144
145 } // namespace
146
147 Builder::Builder()
148 : mSlotDelegate(this)
149 {
150   mParser = Dali::Toolkit::JsonParser::New();
151
152   Property::Map defaultConstants;
153   defaultConstants[TOKEN_STRING(DALI_IMAGE_DIR)]              = AssetManager::GetDaliImagePath();
154   defaultConstants[TOKEN_STRING(DALI_SOUND_DIR)]              = AssetManager::GetDaliSoundPath();
155   defaultConstants[TOKEN_STRING(DALI_STYLE_DIR)]              = AssetManager::GetDaliStylePath();
156   defaultConstants[TOKEN_STRING(DALI_STYLE_IMAGE_DIR)]        = AssetManager::GetDaliStyleImagePath();
157   defaultConstants[TOKEN_STRING(DALI_SHADER_VERSION_PREFIX)]  = Shader::GetShaderVersionPrefix();
158   defaultConstants[TOKEN_STRING(DALI_VERTEX_SHADER_PREFIX)]   = Shader::GetVertexShaderPrefix();
159   defaultConstants[TOKEN_STRING(DALI_FRAGMENT_SHADER_PREFIX)] = Shader::GetFragmentShaderPrefix();
160
161   AddConstants(defaultConstants);
162 }
163
164 void Builder::LoadFromString(std::string const& data, Dali::Toolkit::Builder::UIFormat format)
165 {
166   // parser to get constants and includes only
167   Dali::Toolkit::JsonParser parser = Dali::Toolkit::JsonParser::New();
168
169   if(!parser.Parse(data))
170   {
171     DALI_LOG_WARNING("JSON Parse Error:%d:%d:'%s'\n",
172                      parser.GetErrorLineNumber(),
173                      parser.GetErrorColumn(),
174                      parser.GetErrorDescription().c_str());
175
176     DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
177   }
178   else
179   {
180     // load constant map (allows the user to override the constants in the json after loading)
181     LoadConstants(*parser.GetRoot(), mReplacementMap);
182     // load configuration map
183     LoadConfiguration(*parser.GetRoot(), mConfigurationMap);
184     // merge includes
185     if(OptionalChild includes = IsChild(*parser.GetRoot(), KEYNAME_INCLUDES))
186     {
187       Replacement replacer(mReplacementMap);
188
189       for(TreeNode::ConstIterator iter = (*includes).CBegin(); iter != (*includes).CEnd(); ++iter)
190       {
191         OptionalString filename = replacer.IsString((*iter).second);
192
193         if(filename)
194         {
195 #if defined(DEBUG_ENABLED)
196           DALI_SCRIPT_VERBOSE("Loading Include '%s'\n", (*filename).c_str());
197 #endif
198           LoadFromString(GetFileContents(*filename));
199         }
200       }
201     }
202
203     if(mParser.Parse(data))
204     {
205       // Drop the styles and get them to be rebuilt against the new parse tree as required.
206       mStyles.Clear();
207     }
208     else
209     {
210       DALI_LOG_WARNING("JSON Parse Error:%d:%d:'%s'\n",
211                        mParser.GetErrorLineNumber(),
212                        mParser.GetErrorColumn(),
213                        mParser.GetErrorDescription().c_str());
214
215       DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
216     }
217   }
218
219   DUMP_PARSE_TREE(mParser); // This macro only writes out if DEBUG is enabled and the "DUMP_TREE" constant is defined in the stylesheet.
220   DUMP_TEST_MAPPINGS(mParser);
221
222   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON");
223 }
224
225 void Builder::AddConstants(const Property::Map& map)
226 {
227   mReplacementMap.Merge(map);
228 }
229
230 void Builder::AddConstant(const std::string& key, const Property::Value& value)
231 {
232   mReplacementMap[key] = value;
233 }
234
235 const Property::Map& Builder::GetConfigurations() const
236 {
237   return mConfigurationMap;
238 }
239
240 const Property::Map& Builder::GetConstants() const
241 {
242   return mReplacementMap;
243 }
244
245 const Property::Value& Builder::GetConstant(const std::string& key) const
246 {
247   Property::Value* match = mReplacementMap.Find(key);
248   if(match)
249   {
250     return (*match);
251   }
252   else
253   {
254     static Property::Value invalid;
255     return invalid;
256   }
257 }
258
259 Animation Builder::CreateAnimation(const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor)
260 {
261   Replacement replacement(map, mReplacementMap);
262   return CreateAnimation(animationName, replacement, sourceActor);
263 }
264
265 Animation Builder::CreateAnimation(const std::string& animationName, const Property::Map& map)
266 {
267   Replacement replacement(map, mReplacementMap);
268   return CreateAnimation(animationName, replacement, Stage::GetCurrent().GetRootLayer());
269 }
270
271 Animation Builder::CreateAnimation(const std::string& animationName, Dali::Actor sourceActor)
272 {
273   Replacement replacement(mReplacementMap);
274
275   return CreateAnimation(animationName, replacement, sourceActor);
276 }
277
278 Animation Builder::CreateAnimation(const std::string& animationName)
279 {
280   Replacement replacement(mReplacementMap);
281
282   return CreateAnimation(animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer());
283 }
284
285 BaseHandle Builder::Create(const std::string& templateName)
286 {
287   Replacement replacement(mReplacementMap);
288   return Create(templateName, replacement);
289 }
290
291 BaseHandle Builder::Create(const std::string& templateName, const Property::Map& map)
292 {
293   Replacement replacement(map, mReplacementMap);
294   return Create(templateName, replacement);
295 }
296
297 BaseHandle Builder::CreateFromJson(const std::string& json)
298 {
299   BaseHandle ret;
300
301   // merge in new template, hoping no one else has one named '@temp@'
302   std::string newTemplate =
303     std::string("{\"templates\":{\"@temp@\":") +
304     json +
305     std::string("}}");
306
307   if(mParser.Parse(newTemplate))
308   {
309     Replacement replacement(mReplacementMap);
310     ret = Create("@temp@", replacement);
311   }
312
313   return ret;
314 }
315
316 bool Builder::ApplyFromJson(Handle& handle, const std::string& json)
317 {
318   bool ret = false;
319
320   // merge new style, hoping no one else has one named '@temp@'
321   std::string newStyle =
322     std::string("{\"styles\":{\"@temp@\":") +
323     json +
324     std::string("}}");
325
326   if(mParser.Parse(newStyle))
327   {
328     Replacement replacement(mReplacementMap);
329     ret = ApplyStyle("@temp@", handle, replacement);
330   }
331
332   return ret;
333 }
334
335 bool Builder::ApplyStyle(const std::string& styleName, Handle& handle)
336 {
337   Replacement replacer(mReplacementMap);
338   return ApplyStyle(styleName, handle, replacer);
339 }
340
341 bool Builder::LookupStyleName(const std::string& styleName)
342 {
343   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
344
345   OptionalChild styles = IsChild(*mParser.GetRoot(), KEYNAME_STYLES);
346   OptionalChild style  = IsChildIgnoreCase(*styles, styleName);
347
348   if(styles && style)
349   {
350     return true;
351   }
352   return false;
353 }
354
355 const StylePtr Builder::GetStyle(const std::string& styleName)
356 {
357   const StylePtr* style = mStyles.FindConst(styleName);
358
359   if(style == NULL)
360   {
361     return StylePtr(NULL);
362   }
363   else
364   {
365     return *style;
366   }
367 }
368
369 void Builder::AddActors(Actor toActor)
370 {
371   // 'stage' is the default/by convention section to add from
372   AddActors("stage", toActor);
373 }
374
375 void Builder::AddActors(const std::string& sectionName, Actor toActor)
376 {
377   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
378
379   Property::Map overrideMap;
380   Replacement   replacements(overrideMap, mReplacementMap);
381
382   OptionalChild add = IsChild(*mParser.GetRoot(), sectionName);
383
384   if(add)
385   {
386     for(TreeNode::ConstIterator iter = (*add).CBegin(); iter != (*add).CEnd(); ++iter)
387     {
388       // empty actor adds directly to the stage
389       BaseHandle baseHandle = DoCreate(*mParser.GetRoot(), (*iter).second, Actor(), replacements);
390       Actor      actor      = Actor::DownCast(baseHandle);
391       if(actor)
392       {
393         toActor.Add(actor);
394       }
395     }
396
397     // if were adding the 'stage' section then also check for a render task called stage
398     // to add automatically
399     if("stage" == sectionName)
400     {
401       if(OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "renderTasks"))
402       {
403         if(OptionalChild tasks = IsChild(*renderTasks, "stage"))
404         {
405           CreateRenderTask("stage");
406         }
407       }
408     }
409   }
410 }
411
412 void Builder::CreateRenderTask(const std::string& name)
413 {
414   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
415
416   Replacement constant(mReplacementMap);
417
418   const Stage& stage = Stage::GetCurrent();
419
420   OptionalChild tasks = IsChild(*mParser.GetRoot(), "renderTasks");
421
422   if(tasks)
423   {
424     //
425     // Create the tasks from the current task as generally we want
426     // to setup task zero and onwards. Although this does overwrite
427     // the properties of the current task.
428     //
429     if(OptionalChild renderTask = IsChild(*tasks, name))
430     {
431       RenderTaskList list  = stage.GetRenderTaskList();
432       unsigned int   start = list.GetTaskCount();
433
434       RenderTask task;
435       if(0 == start)
436       {
437         // zero should have already been created by the stage so really
438         // this case should never happen
439         task = list.CreateTask();
440         start++;
441       }
442
443       TreeNode::ConstIterator iter = (*renderTask).CBegin();
444       task                         = list.GetTask(start - 1);
445
446       SetupTask(task, (*iter).second, constant);
447
448       ++iter;
449
450       for(; iter != (*renderTask).CEnd(); ++iter)
451       {
452         task = list.CreateTask();
453         SetupTask(task, (*iter).second, constant);
454       }
455     }
456   }
457 }
458
459 Path Builder::GetPath(const std::string& name)
460 {
461   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
462
463   Path ret;
464
465   PathLut::const_iterator iter(mPathLut.find(name));
466   if(iter != mPathLut.end())
467   {
468     ret = iter->second;
469   }
470   else
471   {
472     if(OptionalChild paths = IsChild(*mParser.GetRoot(), "paths"))
473     {
474       if(OptionalChild path = IsChild(*paths, name))
475       {
476         //points property
477         if(OptionalChild pointsProperty = IsChild(*path, "points"))
478         {
479           Dali::Property::Value points(Property::ARRAY);
480           if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
481           {
482             ret = Path::New();
483             ret.SetProperty(Path::Property::POINTS, points);
484
485             //controlPoints property
486             if(OptionalChild pointsProperty = IsChild(*path, "controlPoints"))
487             {
488               Dali::Property::Value points(Property::ARRAY);
489               if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
490               {
491                 ret.SetProperty(Path::Property::CONTROL_POINTS, points);
492               }
493             }
494             else
495             {
496               //Curvature
497               float curvature(0.25f);
498               if(OptionalFloat pointsProperty = IsFloat(*path, "curvature"))
499               {
500                 curvature = *pointsProperty;
501               }
502               ret.GenerateControlPoints(curvature);
503             }
504
505             //Add the new path to the hash table for paths
506             mPathLut[name] = ret;
507           }
508         }
509         else
510         {
511           //Interpolation points not specified
512           DALI_SCRIPT_WARNING("Interpolation points not specified for path '%s'\n", name.c_str());
513         }
514       }
515     }
516   }
517
518   return ret;
519 }
520
521 PathConstrainer Builder::GetPathConstrainer(const std::string& name)
522 {
523   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
524
525   //Search the pathConstrainer in the LUT
526   size_t count(mPathConstrainerLut.size());
527   for(size_t i(0); i != count; ++i)
528   {
529     if(mPathConstrainerLut[i].name == name)
530     {
531       //PathConstrainer has already been created
532       return mPathConstrainerLut[i].pathConstrainer;
533     }
534   }
535
536   //Create a new PathConstrainer
537   PathConstrainer ret;
538   if(OptionalChild constrainers = IsChild(*mParser.GetRoot(), "constrainers"))
539   {
540     if(OptionalChild pathConstrainer = IsChild(*constrainers, name))
541     {
542       OptionalString constrainerType(IsString(IsChild(*pathConstrainer, "type")));
543       if(!constrainerType)
544       {
545         DALI_SCRIPT_WARNING("Constrainer type not specified for constrainer '%s'\n", name.c_str());
546       }
547       else if(*constrainerType == "PathConstrainer")
548       {
549         //points property
550         if(OptionalChild pointsProperty = IsChild(*pathConstrainer, "points"))
551         {
552           Dali::Property::Value points(Property::ARRAY);
553           if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
554           {
555             ret = PathConstrainer::New();
556             ret.SetProperty(PathConstrainer::Property::POINTS, points);
557
558             //controlPoints property
559             if(OptionalChild pointsProperty = IsChild(*pathConstrainer, "controlPoints"))
560             {
561               Dali::Property::Value points(Property::ARRAY);
562               if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
563               {
564                 ret.SetProperty(PathConstrainer::Property::CONTROL_POINTS, points);
565               }
566
567               //Forward vector
568               OptionalVector3 forward(IsVector3(IsChild(*pathConstrainer, "forward")));
569               if(forward)
570               {
571                 ret.SetProperty(PathConstrainer::Property::FORWARD, *forward);
572               }
573
574               //Add the new constrainer to the vector of PathConstrainer
575               PathConstrainerEntry entry = {name, ret};
576               mPathConstrainerLut.push_back(entry);
577             }
578             else
579             {
580               //Control points not specified
581               DALI_SCRIPT_WARNING("Control points not specified for pathConstrainer '%s'\n", name.c_str());
582             }
583           }
584         }
585         else
586         {
587           //Interpolation points not specified
588           DALI_SCRIPT_WARNING("Interpolation points not specified for pathConstrainer '%s'\n", name.c_str());
589         }
590       }
591       else
592       {
593         DALI_SCRIPT_WARNING("Constrainer '%s' is not a PathConstrainer\n", name.c_str());
594       }
595     }
596   }
597
598   return ret;
599 }
600
601 bool Builder::IsPathConstrainer(const std::string& name)
602 {
603   size_t count(mPathConstrainerLut.size());
604   for(size_t i(0); i != count; ++i)
605   {
606     if(mPathConstrainerLut[i].name == name)
607     {
608       return true;
609     }
610   }
611
612   if(OptionalChild constrainers = IsChild(*mParser.GetRoot(), "constrainers"))
613   {
614     if(OptionalChild constrainer = IsChild(*constrainers, name))
615     {
616       OptionalString constrainerType(IsString(IsChild(*constrainer, "type")));
617       if(!constrainerType)
618       {
619         return false;
620       }
621       else
622       {
623         return *constrainerType == "PathConstrainer";
624       }
625     }
626   }
627   return false;
628 }
629
630 Dali::LinearConstrainer Builder::GetLinearConstrainer(const std::string& name)
631 {
632   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
633
634   //Search the LinearConstrainer in the LUT
635   size_t count(mLinearConstrainerLut.size());
636   for(size_t i(0); i != count; ++i)
637   {
638     if(mLinearConstrainerLut[i].name == name)
639     {
640       //LinearConstrainer has already been created
641       return mLinearConstrainerLut[i].linearConstrainer;
642     }
643   }
644
645   //Create a new LinearConstrainer
646   LinearConstrainer ret;
647   if(OptionalChild constrainers = IsChild(*mParser.GetRoot(), "constrainers"))
648   {
649     if(OptionalChild linearConstrainer = IsChild(*constrainers, name))
650     {
651       OptionalString constrainerType(IsString(IsChild(*linearConstrainer, "type")));
652       if(!constrainerType)
653       {
654         DALI_SCRIPT_WARNING("Constrainer type not specified for constrainer '%s'\n", name.c_str());
655       }
656       else if(*constrainerType == "LinearConstrainer")
657       {
658         //points property
659         if(OptionalChild pointsProperty = IsChild(*linearConstrainer, "value"))
660         {
661           Dali::Property::Value points(Property::ARRAY);
662           if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
663           {
664             ret = Dali::LinearConstrainer::New();
665             ret.SetProperty(LinearConstrainer::Property::VALUE, points);
666
667             //controlPoints property
668             if(OptionalChild pointsProperty = IsChild(*linearConstrainer, "progress"))
669             {
670               Dali::Property::Value points(Property::ARRAY);
671               if(DeterminePropertyFromNode(*pointsProperty, Property::ARRAY, points))
672               {
673                 ret.SetProperty(LinearConstrainer::Property::PROGRESS, points);
674               }
675             }
676             //Add the new constrainer to vector of LinearConstrainer
677             LinearConstrainerEntry entry = {name, ret};
678             mLinearConstrainerLut.push_back(entry);
679           }
680         }
681         else
682         {
683           //Interpolation points not specified
684           DALI_SCRIPT_WARNING("Values not specified for LinearConstrainer '%s'\n", name.c_str());
685         }
686       }
687       else
688       {
689         DALI_SCRIPT_WARNING("Constrainer '%s' is not a LinearConstrainer\n", name.c_str());
690       }
691     }
692   }
693
694   return ret;
695 }
696
697 bool Builder::IsLinearConstrainer(const std::string& name)
698 {
699   // Search the LinearConstrainer in the LUT
700   size_t count(mLinearConstrainerLut.size());
701   for(size_t i(0); i != count; ++i)
702   {
703     if(mLinearConstrainerLut[i].name == name)
704     {
705       return true;
706     }
707   }
708
709   if(OptionalChild constrainers = IsChild(*mParser.GetRoot(), "constrainers"))
710   {
711     if(OptionalChild constrainer = IsChild(*constrainers, name))
712     {
713       OptionalString constrainerType(IsString(IsChild(*constrainer, "type")));
714       if(!constrainerType)
715       {
716         return false;
717       }
718       else
719       {
720         return *constrainerType == "LinearConstrainer";
721       }
722     }
723   }
724   return false;
725 }
726
727 Toolkit::Builder::BuilderSignalType& Builder::QuitSignal()
728 {
729   return mQuitSignal;
730 }
731
732 void Builder::EmitQuitSignal()
733 {
734   mQuitSignal.Emit();
735 }
736
737 Builder::~Builder()
738 {
739 }
740
741 void Builder::LoadConfiguration(const TreeNode& root, Property::Map& intoMap)
742 {
743   Replacement replacer(intoMap);
744
745   if(OptionalChild constants = IsChild(root, "config"))
746   {
747     for(TreeNode::ConstIterator iter = (*constants).CBegin();
748         iter != (*constants).CEnd();
749         ++iter)
750     {
751       Dali::Property::Value property;
752       if((*iter).second.GetName())
753       {
754         DeterminePropertyFromNode((*iter).second, property, replacer);
755
756         // If config is string, find constant and replace it to original value.
757         if((*iter).second.GetType() == TreeNode::STRING)
758         {
759           std::string stringConfigValue;
760           if(property.Get(stringConfigValue))
761           {
762             std::size_t pos = 0;
763
764             while(pos < stringConfigValue.size())
765             {
766               // If we can't find "{","}" pair in stringConfigValue, will out loop.
767               std::size_t leftPos = stringConfigValue.find("{", pos);
768               if(leftPos != std::string::npos)
769               {
770                 std::size_t rightPos = stringConfigValue.find("}", pos + 1);
771
772                 if(rightPos != std::string::npos)
773                 {
774                   // If we find "{","}" pair but can't find matched constant
775                   // try to find other "{","}" pair after current left position.
776                   pos = leftPos + 1;
777
778                   for(uint32_t i = 0; i < mReplacementMap.Count(); i++)
779                   {
780                     Property::Key constant = mReplacementMap.GetKeyAt(i);
781
782                     // Compare string which is between "{" and "}" with constant string
783                     // If they are same, change string in stringConfigValue to mapped constant value.
784                     if(0 == stringConfigValue.compare(leftPos + 1, rightPos - leftPos - 1, constant.stringKey))
785                     {
786                       std::string replaceString;
787                       mReplacementMap.GetValue(i).Get(replaceString);
788
789                       stringConfigValue.replace(leftPos, rightPos - leftPos + 1, replaceString);
790                       pos = leftPos + replaceString.size();
791                       break;
792                     }
793                   }
794                 }
795                 else
796                 {
797                   // If we cannot find constant in const value, will out loop.
798                   pos = stringConfigValue.size();
799                 }
800               }
801               else
802               {
803                 // If we cannot find constant in const value, will out loop.
804                 pos = stringConfigValue.size();
805               }
806             }
807             property = Property::Value(stringConfigValue);
808           }
809         }
810         intoMap[(*iter).second.GetName()] = property;
811       }
812     }
813   }
814 }
815
816 void Builder::LoadConstants(const TreeNode& root, Property::Map& intoMap)
817 {
818   Replacement replacer(intoMap);
819
820   if(OptionalChild constants = IsChild(root, "constants"))
821   {
822     for(TreeNode::ConstIterator iter = (*constants).CBegin();
823         iter != (*constants).CEnd();
824         ++iter)
825     {
826       Dali::Property::Value property;
827       if((*iter).second.GetName())
828       {
829 #if defined(DEBUG_ENABLED)
830         DALI_SCRIPT_VERBOSE("Constant set from json '%s'\n", (*iter).second.GetName());
831 #endif
832         DeterminePropertyFromNode((*iter).second, property, replacer);
833         intoMap[(*iter).second.GetName()] = property;
834       }
835     }
836   }
837
838 #if defined(DEBUG_ENABLED)
839   Property::Value* iter = intoMap.Find("CONFIG_SCRIPT_LOG_LEVEL");
840   if(iter && iter->GetType() == Property::STRING)
841   {
842     std::string logLevel(iter->Get<std::string>());
843     if(logLevel == "NoLogging")
844     {
845       gFilterScript->SetLogLevel(Integration::Log::NoLogging);
846     }
847     else if(logLevel == "Concise")
848     {
849       gFilterScript->SetLogLevel(Integration::Log::Concise);
850     }
851     else if(logLevel == "General")
852     {
853       gFilterScript->SetLogLevel(Integration::Log::General);
854     }
855     else if(logLevel == "Verbose")
856     {
857       gFilterScript->SetLogLevel(Integration::Log::Verbose);
858     }
859   }
860 #endif
861 }
862
863 Animation Builder::CreateAnimation(const std::string& animationName, const Replacement& replacement, Dali::Actor sourceActor)
864 {
865   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
866
867   Animation anim;
868
869   if(OptionalChild animations = IsChild(*mParser.GetRoot(), "animations"))
870   {
871     if(OptionalChild animation = IsChild(*animations, animationName))
872     {
873       anim = Dali::Toolkit::Internal::CreateAnimation(*animation, replacement, sourceActor, this);
874     }
875     else
876     {
877       DALI_SCRIPT_WARNING("Request for Animation called '%s' failed\n", animationName.c_str());
878     }
879   }
880   else
881   {
882     DALI_SCRIPT_WARNING("Request for Animation called '%s' failed (no animation section)\n", animationName.c_str());
883   }
884
885   return anim;
886 }
887
888 BaseHandle Builder::Create(const std::string& templateName, const Replacement& constant)
889 {
890   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
891
892   BaseHandle baseHandle;
893
894   OptionalChild templates = IsChild(*mParser.GetRoot(), KEYNAME_TEMPLATES);
895
896   if(!templates)
897   {
898     DALI_SCRIPT_WARNING("No template section found to CreateFromTemplate\n");
899   }
900   else
901   {
902     OptionalChild childTemplate = IsChild(*templates, templateName);
903     if(!childTemplate)
904     {
905       DALI_SCRIPT_WARNING("Template '%s' does not exist in template section\n", templateName.c_str());
906     }
907     else
908     {
909       OptionalString type = constant.IsString(IsChild(*childTemplate, KEYNAME_TYPE));
910
911       if(!type)
912       {
913         DALI_SCRIPT_WARNING("Cannot create template '%s' as template section is missing 'type'\n", templateName.c_str());
914       }
915       else
916       {
917         baseHandle = DoCreate(*mParser.GetRoot(), *childTemplate, Actor(), constant);
918       }
919     }
920   }
921
922   return baseHandle;
923 }
924
925 /*
926  * Create a dali type from a node.
927  * If parent given and an actor type was created then add it to the parent and
928  * recursively add nodes children.
929  */
930 BaseHandle Builder::DoCreate(const TreeNode& root, const TreeNode& node, Actor parent, const Replacement& replacements)
931 {
932   BaseHandle      baseHandle;
933   TypeInfo        typeInfo;
934   const TreeNode* templateNode = NULL;
935
936   if(OptionalString typeName = IsString(node, KEYNAME_TYPE))
937   {
938     typeInfo = TypeRegistry::Get().GetTypeInfo(*typeName);
939
940     if(!typeInfo)
941     {
942       // a template name is also allowed inplace of the type name
943       OptionalChild templates = IsChild(root, KEYNAME_TEMPLATES);
944
945       if(templates)
946       {
947         if(OptionalChild isTemplate = IsChild(*templates, *typeName))
948         {
949           templateNode = &(*isTemplate);
950
951           if(OptionalString templateTypeName = IsString(*templateNode, KEYNAME_TYPE))
952           {
953             typeInfo = TypeRegistry::Get().GetTypeInfo(*templateTypeName);
954           }
955         }
956       }
957     }
958   }
959
960   if(!typeInfo)
961   {
962     DALI_SCRIPT_WARNING("Cannot create Dali type from node '%s'\n", node.GetName());
963   }
964   else
965   {
966     baseHandle    = typeInfo.CreateInstance();
967     Handle handle = Handle::DownCast(baseHandle);
968     Actor  actor  = Actor::DownCast(handle);
969
970     if(handle)
971     {
972       DALI_SCRIPT_VERBOSE("Create:%s\n", typeInfo.GetName().c_str());
973
974 #if defined(DEBUG_ENABLED)
975       if(handle)
976       {
977         DALI_SCRIPT_VERBOSE("  Is Handle Object=%d\n", (long*)handle.GetObjectPtr());
978         DALI_SCRIPT_VERBOSE("  Is Handle Property Count=%d\n", handle.GetPropertyCount());
979       }
980
981       if(actor)
982       {
983         DALI_SCRIPT_VERBOSE("  Is Actor id=%d\n", actor.GetProperty<int>(Actor::Property::ID));
984       }
985
986       Toolkit::Control control = Toolkit::Control::DownCast(handle);
987       if(control)
988       {
989         DALI_SCRIPT_VERBOSE("  Is Control id=%d\n", actor.GetProperty<int>(Actor::Property::ID));
990       }
991 #endif // DEBUG_ENABLED
992
993       if(templateNode)
994       {
995         ApplyProperties(root, *templateNode, handle, replacements);
996
997         if(OptionalChild actors = IsChild(*templateNode, KEYNAME_ACTORS))
998         {
999           for(TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter)
1000           {
1001             DoCreate(root, (*iter).second, actor, replacements);
1002           }
1003         }
1004       }
1005
1006       if(actor)
1007       {
1008         // add children of all the styles
1009         if(OptionalChild actors = IsChild(node, KEYNAME_ACTORS))
1010         {
1011           for(TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter)
1012           {
1013             DoCreate(root, (*iter).second, actor, replacements);
1014           }
1015         }
1016
1017         // apply style on top as they need the children to exist
1018         ApplyAllStyleProperties(root, node, actor, replacements);
1019
1020         // then add to parent
1021         if(parent)
1022         {
1023           parent.Add(actor);
1024         }
1025       }
1026       else
1027       {
1028         ApplyProperties(root, node, handle, replacements);
1029       }
1030     }
1031     else
1032     {
1033       DALI_SCRIPT_WARNING("Cannot create handle from type '%s'\n", typeInfo.GetName().c_str());
1034     }
1035   }
1036
1037   return baseHandle;
1038 }
1039
1040 void Builder::SetupTask(RenderTask& task, const TreeNode& node, const Replacement& constant)
1041 {
1042   const Stage& stage = Stage::GetCurrent();
1043   Layer        root  = stage.GetRootLayer();
1044
1045   if(OptionalString s = constant.IsString(IsChild(node, "sourceActor")))
1046   {
1047     Actor actor = root.FindChildByName(*s);
1048     if(actor)
1049     {
1050       task.SetSourceActor(actor);
1051     }
1052     else
1053     {
1054       DALI_SCRIPT_WARNING("Cannot find source actor on stage for render task called '%s'\n", (*s).c_str());
1055     }
1056   }
1057
1058   if(OptionalString s = constant.IsString(IsChild(node, "cameraActor")))
1059   {
1060     CameraActor actor = CameraActor::DownCast(root.FindChildByName(*s));
1061     if(actor)
1062     {
1063       task.SetCameraActor(actor);
1064     }
1065     else
1066     {
1067       DALI_SCRIPT_WARNING("Cannot find camera actor on stage for render task called '%s'\n", (*s).c_str());
1068     }
1069   }
1070
1071   if(OptionalString s = constant.IsString(IsChild(node, "screenToFrameBufferFunction")))
1072   {
1073     if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s)
1074     {
1075       task.SetScreenToFrameBufferFunction(RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION);
1076     }
1077     else if("FULLSCREEN_FRAMEBUFFER_FUNCTION" == *s)
1078     {
1079       task.SetScreenToFrameBufferFunction(RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
1080     }
1081     else
1082     {
1083       DALI_SCRIPT_WARNING("todo");
1084     }
1085   }
1086
1087   // other setup is via the property system
1088   SetProperties(node, task, constant);
1089 }
1090
1091 bool Builder::ApplyStyle(const std::string& styleName, Handle& handle, const Replacement& replacement)
1092 {
1093   DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
1094
1095   OptionalChild styles = IsChild(*mParser.GetRoot(), KEYNAME_STYLES);
1096
1097   std::string   styleNameLower(styleName);
1098   OptionalChild style = IsChildIgnoreCase(*styles, styleNameLower);
1099
1100   if(styles && style)
1101   {
1102     ApplyAllStyleProperties(*mParser.GetRoot(), *style, handle, replacement);
1103     return true;
1104   }
1105   else
1106   {
1107     return false;
1108   }
1109 }
1110
1111 void Builder::ApplyAllStyleProperties(const TreeNode& root, const TreeNode& node, Dali::Handle& handle, const Replacement& constant)
1112 {
1113   const char* styleName = node.GetName();
1114
1115   StylePtr style = Style::New();
1116
1117   StylePtr* matchedStyle = NULL;
1118   if(styleName)
1119   {
1120     matchedStyle = mStyles.Find(styleName);
1121     if(!matchedStyle)
1122     {
1123       OptionalChild styleNodes      = IsChild(root, KEYNAME_STYLES);
1124       OptionalChild inheritFromNode = IsChild(node, KEYNAME_INHERIT);
1125       if(!inheritFromNode)
1126       {
1127         inheritFromNode = IsChild(node, KEYNAME_STYLES);
1128       }
1129
1130       if(styleNodes)
1131       {
1132         if(inheritFromNode)
1133         {
1134           TreeNodeList additionalStyleNodes;
1135
1136           CollectAllStyles(*styleNodes, *inheritFromNode, additionalStyleNodes);
1137
1138 #if defined(DEBUG_ENABLED)
1139           for(TreeNode::ConstIterator iter = (*inheritFromNode).CBegin(); iter != (*inheritFromNode).CEnd(); ++iter)
1140           {
1141             if(OptionalString styleName = IsString((*iter).second))
1142             {
1143               DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str());
1144             }
1145           }
1146 #endif
1147
1148           // a style may have other styles, which has other styles etc so we apply in reverse by convention.
1149           for(TreeNodeList::reverse_iterator iter = additionalStyleNodes.rbegin(); iter != additionalStyleNodes.rend(); ++iter)
1150           {
1151             RecordStyle(style, *(*iter), handle, constant);
1152             ApplySignals(root, *(*iter), handle);
1153             ApplyStylesByActor(root, *(*iter), handle, constant);
1154           }
1155         }
1156
1157         RecordStyle(style, node, handle, constant);
1158         mStyles.Add(styleName, style); // shallow copy
1159         matchedStyle = &style;
1160       }
1161     }
1162   }
1163
1164   if(matchedStyle)
1165   {
1166     StylePtr                  style(*matchedStyle);
1167     Dictionary<Property::Map> instancedProperties;
1168     style->ApplyVisualsAndPropertiesRecursively(handle, instancedProperties);
1169   }
1170   else // If there were no styles, instead set properties
1171   {
1172     SetProperties(node, handle, constant);
1173   }
1174   ApplySignals(root, node, handle);
1175   ApplyStylesByActor(root, node, handle, constant);
1176 }
1177
1178 void Builder::RecordStyle(StylePtr           style,
1179                           const TreeNode&    node,
1180                           Dali::Handle&      handle,
1181                           const Replacement& replacements)
1182 {
1183   // With repeated calls, accumulate inherited states, visuals and properties
1184   // but override any with same name
1185
1186   for(TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter)
1187   {
1188     const TreeNode::KeyNodePair& keyValue = *iter;
1189     std::string                  key(keyValue.first);
1190     if(key == KEYNAME_STATES)
1191     {
1192       const TreeNode& states = keyValue.second;
1193       if(states.GetType() != TreeNode::OBJECT)
1194       {
1195         DALI_LOG_WARNING("RecordStyle() Node \"%s\" is not a JSON object\n", key.c_str());
1196         continue;
1197       }
1198
1199       for(TreeNode::ConstIterator iter = states.CBegin(); iter != states.CEnd(); ++iter)
1200       {
1201         const TreeNode& stateNode = (*iter).second;
1202         const char*     stateName = stateNode.GetName();
1203         if(stateNode.GetType() != TreeNode::OBJECT)
1204         {
1205           DALI_LOG_WARNING("RecordStyle() Node \"%s\" is not a JSON object\n", stateName);
1206           continue;
1207         }
1208
1209         StylePtr* stylePtr = style->subStates.Find(stateName);
1210         if(stylePtr)
1211         {
1212           StylePtr subState(*stylePtr);
1213           RecordStyle(subState, stateNode, handle, replacements);
1214         }
1215         else
1216         {
1217           StylePtr subState = Style::New();
1218           RecordStyle(subState, stateNode, handle, replacements);
1219           style->subStates.Add(stateName, subState);
1220         }
1221       }
1222     }
1223     else if(key == KEYNAME_VISUALS)
1224     {
1225       for(TreeNode::ConstIterator iter = keyValue.second.CBegin(); iter != keyValue.second.CEnd(); ++iter)
1226       {
1227         // Each key in this table should be a property name matching a visual.
1228         const TreeNode::KeyNodePair& visual = *iter;
1229         Dali::Property::Value        property(Property::MAP);
1230         if(DeterminePropertyFromNode(visual.second, Property::MAP, property, replacements))
1231         {
1232           Property::Map* mapPtr = style->visuals.Find(visual.first);
1233           if(mapPtr)
1234           {
1235             // Override existing visuals
1236             mapPtr->Clear();
1237             mapPtr->Merge(*property.GetMap());
1238           }
1239           else
1240           {
1241             Property::Map* map = property.GetMap();
1242             if(map)
1243             {
1244               style->visuals.Add(visual.first, *map);
1245             }
1246           }
1247         }
1248       }
1249     }
1250     else if(key == KEYNAME_ENTRY_TRANSITION)
1251     {
1252       RecordTransitionData(keyValue, style->entryTransition, replacements);
1253     }
1254     else if(key == KEYNAME_EXIT_TRANSITION)
1255     {
1256       RecordTransitionData(keyValue, style->exitTransition, replacements);
1257     }
1258     else if(key == KEYNAME_TRANSITIONS)
1259     {
1260       RecordTransitions(keyValue, style->transitions, replacements);
1261     }
1262     else if(key == KEYNAME_TYPE ||
1263             key == KEYNAME_ACTORS ||
1264             key == KEYNAME_SIGNALS ||
1265             key == KEYNAME_STYLES ||
1266             key == KEYNAME_MAPPINGS ||
1267             key == KEYNAME_INHERIT)
1268     {
1269       continue;
1270     }
1271     else // It's a property
1272     {
1273       Property::Index index;
1274       Property::Value value;
1275       if(MapToTargetProperty(handle, key, keyValue.second, replacements, index, value))
1276       {
1277         Property::Value* existingValuePtr = style->properties.Find(index);
1278         if(existingValuePtr != NULL)
1279         {
1280           *existingValuePtr = value; // Overwrite existing property.
1281         }
1282         else
1283         {
1284           style->properties.Add(index, value);
1285         }
1286       }
1287     }
1288   }
1289 }
1290
1291 void Builder::RecordTransitions(
1292   const TreeNode::KeyNodePair& keyValue,
1293   Property::Array&             value,
1294   const Replacement&           replacements)
1295 {
1296   //@todo add new transitions to style.transitions
1297   //      override existing transitions. A transition matches on target & property name
1298   const TreeNode& node = keyValue.second;
1299   if(node.GetType() == TreeNode::ARRAY)
1300   {
1301     Dali::Property::Value property(Property::ARRAY);
1302     if(DeterminePropertyFromNode(node, Property::ARRAY, property, replacements))
1303     {
1304       value = *property.GetArray();
1305     }
1306   }
1307   else if(node.GetType() == TreeNode::OBJECT)
1308   {
1309     Dali::Property::Value property(Property::MAP);
1310     if(DeterminePropertyFromNode(node, Property::MAP, property, replacements))
1311     {
1312       Property::Array propertyArray;
1313       propertyArray.Add(property);
1314       value = propertyArray;
1315     }
1316   }
1317   else
1318   {
1319     DALI_LOG_WARNING("RecordStyle() Node \"%s\" is not a JSON array or object\n", keyValue.first);
1320   }
1321 }
1322
1323 void Builder::RecordTransitionData(
1324   const TreeNode::KeyNodePair& keyValue,
1325   Toolkit::TransitionData&     transitionData,
1326   const Replacement&           replacements)
1327 {
1328   const TreeNode& node = keyValue.second;
1329   if(node.GetType() == TreeNode::ARRAY)
1330   {
1331     Dali::Property::Value property(Property::ARRAY);
1332     if(DeterminePropertyFromNode(keyValue.second, Property::ARRAY, property, replacements))
1333     {
1334       transitionData = Toolkit::TransitionData::New(*property.GetArray());
1335     }
1336   }
1337   else if(node.GetType() == TreeNode::OBJECT)
1338   {
1339     Dali::Property::Value property(Property::MAP);
1340     if(DeterminePropertyFromNode(keyValue.second, Property::MAP, property, replacements))
1341     {
1342       transitionData = Toolkit::TransitionData::New(*property.GetMap());
1343     }
1344   }
1345 }
1346
1347 // Set properties from node on handle.
1348 void Builder::ApplyProperties(const TreeNode& root, const TreeNode& node, Dali::Handle& handle, const Replacement& constant)
1349 {
1350   SetProperties(node, handle, constant);
1351   ApplySignals(root, node, handle);
1352 }
1353
1354 void Builder::ApplySignals(const TreeNode& root, const TreeNode& node, Dali::Handle& handle)
1355 {
1356   Actor actor = Actor::DownCast(handle);
1357   if(actor)
1358   {
1359     // add signals
1360     SetupSignalAction(mSlotDelegate.GetConnectionTracker(), root, node, actor, this);
1361     SetupPropertyNotification(mSlotDelegate.GetConnectionTracker(), root, node, actor, this);
1362   }
1363 }
1364
1365 // Appling by style helper
1366 // use FindChildByName() to apply properties referenced in KEYNAME_ACTORS in the node
1367 void Builder::ApplyStylesByActor(const TreeNode& root, const TreeNode& node, Dali::Handle& handle, const Replacement& constant)
1368 {
1369   if(Dali::Actor actor = Dali::Actor::DownCast(handle))
1370   {
1371     if(const TreeNode* actors = node.GetChild(KEYNAME_ACTORS))
1372     {
1373       // in a style the actor subtree properties referenced by actor name
1374       for(TreeConstIter iter = actors->CBegin(); iter != actors->CEnd(); ++iter)
1375       {
1376         Dali::Actor foundActor;
1377
1378         if((*iter).first)
1379         {
1380           foundActor = actor.FindChildByName((*iter).first);
1381         }
1382
1383         if(!foundActor)
1384         {
1385           DALI_SCRIPT_VERBOSE("Cannot find actor in style application '%s'\n", (*iter).first);
1386         }
1387         else
1388         {
1389           DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first);
1390           ApplyProperties(root, (*iter).second, foundActor, constant);
1391         }
1392       }
1393     }
1394   }
1395 }
1396
1397 /*
1398  * Sets the handle properties found in the tree node
1399  */
1400 void Builder::SetProperties(const TreeNode& node, Handle& handle, const Replacement& constant)
1401 {
1402   if(handle)
1403   {
1404     for(TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter)
1405     {
1406       const TreeNode::KeyNodePair& keyChild = *iter;
1407
1408       std::string key(keyChild.first);
1409
1410       // ignore special fields;
1411       if(key == KEYNAME_TYPE ||
1412          key == KEYNAME_ACTORS ||
1413          key == KEYNAME_SIGNALS ||
1414          key == KEYNAME_STYLES ||
1415          key == KEYNAME_MAPPINGS ||
1416          key == KEYNAME_INHERIT ||
1417          key == KEYNAME_STATES ||
1418          key == KEYNAME_VISUALS ||
1419          key == KEYNAME_ENTRY_TRANSITION ||
1420          key == KEYNAME_EXIT_TRANSITION ||
1421          key == KEYNAME_TRANSITIONS)
1422       {
1423         continue;
1424       }
1425
1426       Property::Index index;
1427       Property::Value value;
1428
1429       bool mapped = MapToTargetProperty(handle, key, keyChild.second, constant, index, value);
1430       if(mapped)
1431       {
1432         DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str());
1433
1434         handle.SetProperty(index, value);
1435       }
1436
1437       // Add custom properties
1438       SetCustomProperties(node, handle, constant, PROPERTIES, Property::READ_WRITE);
1439       SetCustomProperties(node, handle, constant, ANIMATABLE_PROPERTIES, Property::ANIMATABLE);
1440
1441     } // for property nodes
1442   }
1443   else
1444   {
1445     DALI_SCRIPT_WARNING("Style applied to empty handle\n");
1446   }
1447 }
1448
1449 bool Builder::MapToTargetProperty(
1450   Handle&            propertyObject,
1451   const std::string& key,
1452   const TreeNode&    node,
1453   const Replacement& constant,
1454   Property::Index&   index,
1455   Property::Value&   value)
1456 {
1457   bool mapped = false;
1458
1459   index = propertyObject.GetPropertyIndex(key);
1460   if(Property::INVALID_INDEX != index)
1461   {
1462     Property::Type type = propertyObject.GetPropertyType(index);
1463
1464     // if node.value is a mapping, get the property value from the "mappings" table
1465     if(node.GetType() == TreeNode::STRING)
1466     {
1467       std::string mappingKey;
1468       if(GetMappingKey(node.GetString(), mappingKey))
1469       {
1470         OptionalChild mappingRoot = IsChild(mParser.GetRoot(), KEYNAME_MAPPINGS);
1471         mapped                    = GetPropertyMap(*mappingRoot, mappingKey.c_str(), type, value);
1472       }
1473     }
1474     if(!mapped)
1475     {
1476       mapped = DeterminePropertyFromNode(node, type, value, constant);
1477       if(!mapped)
1478       {
1479         // Just determine the property from the node and if it's valid, let the property object handle it
1480         DeterminePropertyFromNode(node, value, constant);
1481         mapped = (value.GetType() != Property::NONE);
1482       }
1483     }
1484   }
1485   else
1486   {
1487     DALI_LOG_ERROR("Key '%s' not found.\n", key.c_str());
1488   }
1489   return mapped;
1490 }
1491
1492 bool Builder::GetPropertyMap(const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value)
1493 {
1494   KeyStack keyStack;
1495   return RecursePropertyMap(mappingRoot, keyStack, theKey, propertyType, value);
1496 }
1497
1498 bool Builder::RecursePropertyMap(const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value)
1499 {
1500   Replacement replacer(mReplacementMap);
1501   bool        result = false;
1502
1503   keyStack.push_back(theKey);
1504
1505   for(TreeNode::ConstIterator iter = mappingRoot.CBegin(); iter != mappingRoot.CEnd(); ++iter)
1506   {
1507     std::string aKey((*iter).first);
1508     if(aKey.compare(theKey) == 0)
1509     {
1510       if(propertyType == Property::NONE)
1511       {
1512         DeterminePropertyFromNode((*iter).second, value, replacer);
1513         result = true;
1514       }
1515       else
1516       {
1517         result = DeterminePropertyFromNode((*iter).second, propertyType, value, replacer);
1518       }
1519
1520       if(result)
1521       {
1522         ConvertChildValue(mappingRoot, keyStack, value);
1523       }
1524       break;
1525     }
1526   }
1527   keyStack.pop_back();
1528
1529   return result;
1530 }
1531
1532 bool Builder::ConvertChildValue(const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& child)
1533 {
1534   bool result = false;
1535
1536   switch(child.GetType())
1537   {
1538     case Property::STRING:
1539     {
1540       std::string value;
1541       if(child.Get(value))
1542       {
1543         std::string key;
1544         if(GetMappingKey(value, key))
1545         {
1546           // Check key for cycles:
1547           result = true;
1548           for(KeyStack::iterator iter = keyStack.begin(); iter != keyStack.end(); ++iter)
1549           {
1550             if(key.compare(*iter) == 0)
1551             {
1552               // key is already in stack; stop.
1553               DALI_LOG_WARNING("Detected cycle in stylesheet mapping table:%s\n", key.c_str());
1554               child  = Property::Value("");
1555               result = false;
1556               break;
1557             }
1558           }
1559
1560           if(result)
1561           {
1562             // The following call will overwrite the child with the value
1563             // from the mapping.
1564             RecursePropertyMap(mappingRoot, keyStack, key.c_str(), Property::NONE, child);
1565             result = true;
1566           }
1567         }
1568       }
1569       break;
1570     }
1571
1572     case Property::MAP:
1573     {
1574       Property::Map* map = child.GetMap();
1575       if(map)
1576       {
1577         for(Property::Map::SizeType i = 0; i < map->Count(); ++i)
1578         {
1579           Property::Value& currentChild = map->GetValue(i);
1580           ConvertChildValue(mappingRoot, keyStack, currentChild);
1581         }
1582       }
1583       break;
1584     }
1585
1586     case Property::ARRAY:
1587     {
1588       Property::Array* array = child.GetArray();
1589       if(array)
1590       {
1591         for(Property::Array::SizeType i = 0; i < array->Count(); ++i)
1592         {
1593           Property::Value& currentChild = array->GetElementAt(i);
1594           ConvertChildValue(mappingRoot, keyStack, currentChild);
1595         }
1596       }
1597       break;
1598     }
1599
1600     default:
1601       // Ignore other types.
1602       break;
1603   }
1604
1605   return result;
1606 }
1607
1608 void Builder::SetCustomProperties(const TreeNode& node, Handle& handle, const Replacement& constant, const std::string& childName, Property::AccessMode accessMode)
1609 {
1610   // Add custom properties
1611   if(OptionalChild customPropertiesChild = IsChild(node, childName))
1612   {
1613     const TreeNode&     customPropertiesNode = *customPropertiesChild;
1614     const TreeConstIter endIter              = customPropertiesNode.CEnd();
1615     for(TreeConstIter iter = customPropertiesNode.CBegin(); endIter != iter; ++iter)
1616     {
1617       const TreeNode::KeyNodePair& keyChild = *iter;
1618       std::string                  key(keyChild.first);
1619       Property::Value              value;
1620       DeterminePropertyFromNode(keyChild.second, value, constant);
1621
1622       // Register/Set property.
1623       handle.RegisterProperty(key, value, accessMode);
1624     }
1625   }
1626 }
1627
1628 } // namespace Internal
1629
1630 } // namespace Toolkit
1631
1632 } // namespace Dali