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