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