[dali_2.3.20] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / builder / builder-impl.cpp
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // 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 = rightPos + 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                       if(DALI_LIKELY(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                 }
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 subState(*stylePtr);
1214           RecordStyle(subState, 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& currentChild = map->GetValue(i);
1581           ConvertChildValue(mappingRoot, keyStack, currentChild);
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& currentChild = array->GetElementAt(i);
1595           ConvertChildValue(mappingRoot, keyStack, currentChild);
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