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