Updating Builder and Control to handle styled States
[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.FindCaseInsensitiveC( 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.FindCaseInsensitive( 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     style->ApplyVisualsAndPropertiesRecursively( handle ); // (recurses through states)
1143   }
1144   else // If there were no styles, instead set properties
1145   {
1146     SetProperties( node, handle, constant );
1147   }
1148   ApplySignals( root, node, handle );
1149   ApplyStylesByActor( root, node, handle, constant );
1150 }
1151
1152 void Builder::RecordStyle( StylePtr           style,
1153                            const TreeNode&    node,
1154                            Dali::Handle&      handle,
1155                            const Replacement& replacements )
1156 {
1157   // With repeated calls, accumulate inherited states, visuals and properties
1158   // but override any with same name
1159
1160   for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter )
1161   {
1162     const TreeNode::KeyNodePair& keyValue = *iter;
1163     std::string key( keyValue.first );
1164     if( key == KEYNAME_STATES )
1165     {
1166       const TreeNode& states = keyValue.second;
1167       if( states.GetType() != TreeNode::OBJECT )
1168       {
1169         DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON object\n", key.c_str() );
1170         continue;
1171       }
1172
1173       for( TreeNode::ConstIterator iter = states.CBegin(); iter != states.CEnd(); ++iter )
1174       {
1175         const TreeNode& stateNode = (*iter).second;
1176         const char* stateName = stateNode.GetName();
1177         if( stateNode.GetType() != TreeNode::OBJECT )
1178         {
1179           DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON object\n", stateName );
1180           continue;
1181         }
1182
1183         StylePtr* stylePtr = style->subStates.FindCaseInsensitive( stateName );
1184         if( stylePtr )
1185         {
1186           StylePtr style(*stylePtr);
1187           RecordStyle( style, stateNode, handle, replacements );
1188         }
1189         else
1190         {
1191           StylePtr subState = Style::New();
1192           RecordStyle( subState, stateNode, handle, replacements );
1193           style->subStates.Add( stateName, subState );
1194         }
1195       }
1196     }
1197     else if( key == KEYNAME_VISUALS )
1198     {
1199       for( TreeNode::ConstIterator iter = keyValue.second.CBegin(); iter != keyValue.second.CEnd(); ++iter )
1200       {
1201         // Each key in this table should be a property name matching a visual.
1202         const TreeNode::KeyNodePair& visual = *iter;
1203         Dali::Property::Value property(Property::MAP);
1204         if( DeterminePropertyFromNode( visual.second, Property::MAP, property, replacements ) )
1205         {
1206           Property::Map* mapPtr = style->visuals.FindCaseInsensitive( visual.first );
1207           if( mapPtr )
1208           {
1209             // Override existing visuals
1210             mapPtr->Clear();
1211             mapPtr->Merge(*property.GetMap());
1212           }
1213           else
1214           {
1215             style->visuals.Add(visual.first, *property.GetMap());
1216           }
1217         }
1218       }
1219     }
1220     else if( key == KEYNAME_ENTRY_TRANSITION )
1221     {
1222       Dali::Property::Value property(Property::MAP);
1223       if( DeterminePropertyFromNode( keyValue.second, Property::MAP, property, replacements ) )
1224       {
1225         style->entryTransition = Toolkit::TransitionData::New( *property.GetMap() );
1226       }
1227     }
1228     else if( key == KEYNAME_EXIT_TRANSITION )
1229     {
1230       Dali::Property::Value property(Property::MAP);
1231       if( DeterminePropertyFromNode( keyValue.second, Property::MAP, property, replacements ) )
1232       {
1233         style->exitTransition = Toolkit::TransitionData::New( *property.GetMap() );
1234       }
1235     }
1236     else if( key == KEYNAME_TRANSITIONS )
1237     {
1238       //@todo add new transitions to style.transitions
1239       //      override existing transitions. A transition matches on target & property name
1240       const TreeNode& node = keyValue.second;
1241       if( node.GetType() == TreeNode::ARRAY )
1242       {
1243         Dali::Property::Value property(Property::ARRAY);
1244         if( DeterminePropertyFromNode( node, Property::ARRAY, property, replacements ) )
1245         {
1246           style->transitions = *property.GetArray();
1247         }
1248       }
1249       else if( node.GetType() == TreeNode::OBJECT )
1250       {
1251         Dali::Property::Value property(Property::MAP);
1252         if( DeterminePropertyFromNode( node, Property::MAP, property, replacements ) )
1253         {
1254           Property::Array propertyArray;
1255           propertyArray.Add( property );
1256           style->transitions = propertyArray;
1257         }
1258       }
1259       else
1260       {
1261         DALI_LOG_WARNING( "RecordState() Node \"%s\" is not a JSON array or object\n", key.c_str() );
1262       }
1263     }
1264     else if( key == KEYNAME_TYPE ||
1265              key == KEYNAME_ACTORS ||
1266              key == KEYNAME_SIGNALS ||
1267              key == KEYNAME_STYLES ||
1268              key == KEYNAME_MAPPINGS ||
1269              key == KEYNAME_INHERIT )
1270     {
1271       continue;
1272     }
1273     else // It's a property
1274     {
1275       Property::Index index;
1276       Property::Value value;
1277       if( MapToTargetProperty( handle, key, keyValue.second, replacements, index, value ) )
1278       {
1279         Property::Value* existingValuePtr = style->properties.Find( index );
1280         if( existingValuePtr != NULL )
1281         {
1282           *existingValuePtr = value; // Overwrite existing property.
1283         }
1284         else
1285         {
1286           style->properties.Add( index, value );
1287         }
1288       }
1289     }
1290   }
1291 }
1292
1293 // Set properties from node on handle.
1294 void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node,
1295                                Dali::Handle& handle, const Replacement& constant )
1296 {
1297   SetProperties( node, handle, constant );
1298   ApplySignals( root, node, handle );
1299 }
1300
1301 void Builder::ApplySignals(const TreeNode& root, const TreeNode& node, Dali::Handle& handle )
1302 {
1303   Actor actor = Actor::DownCast(handle);
1304   if( actor )
1305   {
1306     // add signals
1307     SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
1308     SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
1309   }
1310 }
1311
1312
1313 // Appling by style helper
1314 // use FindChildByName() to apply properties referenced in KEYNAME_ACTORS in the node
1315 void Builder::ApplyStylesByActor(  const TreeNode& root, const TreeNode& node,
1316                                    Dali::Handle& handle, const Replacement& constant )
1317 {
1318   if( Dali::Actor actor = Dali::Actor::DownCast( handle ) )
1319   {
1320     if( const TreeNode* actors = node.GetChild( KEYNAME_ACTORS ) )
1321     {
1322       // in a style the actor subtree properties referenced by actor name
1323       for( TreeConstIter iter = actors->CBegin(); iter != actors->CEnd(); ++iter )
1324       {
1325         Dali::Actor foundActor;
1326
1327         if( (*iter).first )
1328         {
1329           foundActor = actor.FindChildByName( (*iter).first );
1330         }
1331
1332         if( !foundActor )
1333         {
1334           DALI_SCRIPT_VERBOSE("Cannot find actor in style application '%s'\n", (*iter).first);
1335         }
1336         else
1337         {
1338           DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first);
1339           ApplyProperties( root, (*iter).second, foundActor, constant );
1340         }
1341       }
1342     }
1343   }
1344 }
1345
1346 /*
1347  * Sets the handle properties found in the tree node
1348  */
1349 void Builder::SetProperties( const TreeNode& node, Handle& handle, const Replacement& constant )
1350 {
1351   if( handle )
1352   {
1353     for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter )
1354     {
1355       const TreeNode::KeyNodePair& keyChild = *iter;
1356
1357       std::string key( keyChild.first );
1358
1359       // ignore special fields;
1360       if( key == KEYNAME_TYPE ||
1361           key == KEYNAME_ACTORS ||
1362           key == KEYNAME_SIGNALS ||
1363           key == KEYNAME_STYLES ||
1364           key == KEYNAME_MAPPINGS ||
1365           key == KEYNAME_INHERIT ||
1366           key == KEYNAME_STATES ||
1367           key == KEYNAME_VISUALS ||
1368           key == KEYNAME_ENTRY_TRANSITION ||
1369           key == KEYNAME_EXIT_TRANSITION ||
1370           key == KEYNAME_TRANSITIONS )
1371       {
1372         continue;
1373       }
1374
1375       Property::Index index;
1376       Property::Value value;
1377
1378       bool mapped = MapToTargetProperty( handle, key, keyChild.second, constant, index, value );
1379       if( mapped )
1380       {
1381         DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str() );
1382
1383         handle.SetProperty( index, value );
1384       }
1385
1386       // Add custom properties
1387       SetCustomProperties(node, handle, constant, PROPERTIES, Property::READ_WRITE);
1388       SetCustomProperties(node, handle, constant, ANIMATABLE_PROPERTIES, Property::ANIMATABLE);
1389
1390     } // for property nodes
1391   }
1392   else
1393   {
1394     DALI_SCRIPT_WARNING("Style applied to empty handle\n");
1395   }
1396 }
1397
1398 bool Builder::MapToTargetProperty(
1399   Handle&            propertyObject,
1400   const std::string& key,
1401   const TreeNode&    node,
1402   const Replacement& constant,
1403   Property::Index&   index,
1404   Property::Value&   value )
1405 {
1406   bool mapped = false;
1407
1408   index = propertyObject.GetPropertyIndex( key );
1409   if( Property::INVALID_INDEX != index )
1410   {
1411     Property::Type type = propertyObject.GetPropertyType(index);
1412
1413     // if node.value is a mapping, get the property value from the "mappings" table
1414     if( node.GetType() == TreeNode::STRING )
1415     {
1416       std::string mappingKey;
1417       if( GetMappingKey( node.GetString(), mappingKey) )
1418       {
1419         OptionalChild mappingRoot = IsChild( mParser.GetRoot(), KEYNAME_MAPPINGS );
1420         mapped = GetPropertyMap( *mappingRoot, mappingKey.c_str(), type, value );
1421       }
1422     }
1423     if( ! mapped )
1424     {
1425       mapped = DeterminePropertyFromNode( node, type, value, constant );
1426       if( ! mapped )
1427       {
1428         // Just determine the property from the node and if it's valid, let the property object handle it
1429         DeterminePropertyFromNode( node, value, constant );
1430         mapped = ( value.GetType() != Property::NONE );
1431       }
1432     }
1433   }
1434   else
1435   {
1436     DALI_LOG_ERROR("Key '%s' not found.\n", key.c_str());
1437   }
1438   return mapped;
1439 }
1440
1441 bool Builder::GetPropertyMap( const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value )
1442 {
1443   KeyStack keyStack;
1444   return RecursePropertyMap( mappingRoot, keyStack, theKey, propertyType, value );
1445 }
1446
1447 bool Builder::RecursePropertyMap( const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value )
1448 {
1449   Replacement replacer( mReplacementMap );
1450   bool result = false;
1451
1452   keyStack.push_back( theKey );
1453
1454   for( TreeNode::ConstIterator iter = mappingRoot.CBegin(); iter != mappingRoot.CEnd(); ++iter )
1455   {
1456     std::string aKey( (*iter).first );
1457     if( aKey.compare( theKey ) == 0 )
1458     {
1459       if( propertyType == Property::NONE )
1460       {
1461         DeterminePropertyFromNode( (*iter).second, value, replacer );
1462         result = true;
1463       }
1464       else
1465       {
1466         result = DeterminePropertyFromNode( (*iter).second, propertyType, value, replacer );
1467       }
1468
1469       if( result )
1470       {
1471         ConvertChildValue(mappingRoot, keyStack, value);
1472       }
1473       break;
1474     }
1475   }
1476   keyStack.pop_back();
1477
1478   return result;
1479 }
1480
1481 bool Builder::ConvertChildValue( const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& child )
1482 {
1483   bool result = false;
1484
1485   switch( child.GetType() )
1486   {
1487     case Property::STRING:
1488     {
1489       std::string value;
1490       if( child.Get( value ) )
1491       {
1492         std::string key;
1493         if( GetMappingKey( value, key ) )
1494         {
1495           // Check key for cycles:
1496           result=true;
1497           for( KeyStack::iterator iter = keyStack.begin() ; iter != keyStack.end(); ++iter )
1498           {
1499             if( key.compare(*iter) == 0 )
1500             {
1501               // key is already in stack; stop.
1502               DALI_LOG_WARNING("Detected cycle in stylesheet mapping table:%s\n", key.c_str());
1503               child = Property::Value("");
1504               result=false;
1505               break;
1506             }
1507           }
1508
1509           if( result )
1510           {
1511             // The following call will overwrite the child with the value
1512             // from the mapping.
1513             RecursePropertyMap( mappingRoot, keyStack, key.c_str(), Property::NONE, child );
1514             result = true;
1515           }
1516         }
1517       }
1518       break;
1519     }
1520
1521     case Property::MAP:
1522     {
1523       Property::Map* map = child.GetMap();
1524       if( map )
1525       {
1526         for( Property::Map::SizeType i=0; i < map->Count(); ++i )
1527         {
1528           Property::Value& child = map->GetValue(i);
1529           ConvertChildValue(mappingRoot, keyStack, child);
1530         }
1531       }
1532       break;
1533     }
1534
1535     case Property::ARRAY:
1536     {
1537       Property::Array* array = child.GetArray();
1538       if( array )
1539       {
1540         for( Property::Array::SizeType i=0; i < array->Count(); ++i )
1541         {
1542           Property::Value& child = array->GetElementAt(i);
1543           ConvertChildValue(mappingRoot, keyStack, child);
1544         }
1545       }
1546       break;
1547     }
1548
1549     default:
1550       // Ignore other types.
1551       break;
1552   }
1553
1554   return result;
1555 }
1556
1557 void Builder::SetCustomProperties( const TreeNode& node, Handle& handle, const Replacement& constant,
1558                           const std::string& childName, Property::AccessMode accessMode )
1559 {
1560   // Add custom properties
1561   if( OptionalChild customPropertiesChild = IsChild(node, childName) )
1562   {
1563     const TreeNode& customPropertiesNode = *customPropertiesChild;
1564     const TreeConstIter endIter = customPropertiesNode.CEnd();
1565     for( TreeConstIter iter = customPropertiesNode.CBegin(); endIter != iter; ++iter )
1566     {
1567       const TreeNode::KeyNodePair& keyChild = *iter;
1568       std::string key( keyChild.first );
1569       Property::Value value;
1570       DeterminePropertyFromNode( keyChild.second, value, constant );
1571
1572       // Register/Set property.
1573       handle.RegisterProperty( key, value, accessMode );
1574     }
1575   }
1576 }
1577
1578
1579 } // namespace Internal
1580
1581 } // namespace Toolkit
1582
1583 } // namespace Dali