926842a7071943a25bfd5e977382e1e3e5b9ea35
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / builder / tree-node-manipulator.cpp
1 /*
2  * Copyright (c) 2014 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 // EXTERNAL INCLUDES
19 #include <cstring>
20 #include <sstream>
21
22 // INTERNAL INCLUDES
23 #include <dali-toolkit/internal/builder/tree-node-manipulator.h>
24
25 #include <dali-toolkit/devel-api/builder/tree-node.h>
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 namespace
37 {
38
39 void Indent(std::ostream& o, int level, int indentWidth)
40 {
41   for (int i = 0; i < level*indentWidth; ++i)
42   {
43     o << " ";
44   }
45 }
46
47 std::string EscapeQuotes( const char* aString)
48 {
49   std::string escapedString;
50   int length = strlen(aString);
51   escapedString.reserve(length);
52
53   const char* end = aString+length;
54   for( const char* iter = aString; iter != end ; ++iter)
55   {
56     if(*iter != '\"')
57     {
58       escapedString.push_back(*iter);
59     }
60     else
61     {
62       escapedString.append("\\\"");
63     }
64   }
65   return escapedString;
66 }
67
68 } // anonymous namespace
69
70 TreeNodeManipulator::TreeNodeManipulator(TreeNode* node)
71   : mNode(node)
72 {
73 }
74
75 TreeNode* TreeNodeManipulator::NewTreeNode()
76 {
77   return new TreeNode();
78 }
79
80 void TreeNodeManipulator::ShallowCopy(const TreeNode* from, TreeNode* to)
81 {
82   DALI_ASSERT_DEBUG(from);
83   DALI_ASSERT_DEBUG(to);
84
85   if( from )
86   {
87     to->mName         = from->mName;
88     to->mType         = from->mType;
89     to->mSubstituion  = from->mSubstituion;
90     switch(from->mType)
91     {
92       case TreeNode::INTEGER:
93       {
94         to->mIntValue = from->mIntValue;
95         break;
96       }
97       case TreeNode::FLOAT:
98       {
99         to->mFloatValue = from->mFloatValue;
100         break;
101       }
102       case TreeNode::STRING:
103       {
104         to->mStringValue = from->mStringValue;
105         break;
106       }
107       case TreeNode::BOOLEAN:
108       {
109         to->mIntValue = from->mIntValue;
110         break;
111       }
112       case TreeNode::IS_NULL:
113       case TreeNode::OBJECT:
114       case TreeNode::ARRAY:
115       {
116         break;
117       }
118     }
119   }
120
121 }
122
123 void TreeNodeManipulator::MoveNodeStrings(VectorCharIter& start, const VectorCharIter& sentinel)
124 {
125   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
126   if(mNode->mName)
127   {
128     mNode->mName = CopyString(mNode->mName, start, sentinel);
129   }
130
131   if(TreeNode::STRING == mNode->mType)
132   {
133     mNode->mStringValue = CopyString(mNode->mStringValue, start, sentinel);
134   }
135 }
136
137 void TreeNodeManipulator::MoveStrings(VectorCharIter& start, const VectorCharIter& sentinel)
138 {
139   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
140   TreeNodeManipulator modify(mNode);
141   modify.MoveNodeStrings(start, sentinel);
142   RecurseMoveChildStrings(start, sentinel);
143 }
144
145 void TreeNodeManipulator::RecurseMoveChildStrings(VectorCharIter& start, const VectorCharIter& sentinel)
146 {
147   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
148
149   TreeNode* child = mNode->mFirstChild;
150   while(child)
151   {
152     TreeNodeManipulator manipChild(child);
153     manipChild.MoveNodeStrings(start, sentinel);
154     child = child->mNextSibling;
155   }
156
157   child = mNode->mFirstChild;
158   while(child)
159   {
160     TreeNodeManipulator manipChild(child);
161     manipChild.RecurseMoveChildStrings(start, sentinel);
162     child = child->mNextSibling;
163   }
164 }
165
166 void TreeNodeManipulator::RemoveChildren()
167 {
168   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
169
170   CollectNodes collector;
171
172   DepthFirst( mNode, collector );
173
174   for(CollectNodes::iterator iter = collector.nodes.begin(); iter != collector.nodes.end(); ++iter)
175   {
176     if( *iter != mNode)
177     {
178       delete *iter;
179     }
180   }
181
182   mNode->mFirstChild = NULL;
183   mNode->mLastChild  = NULL;
184 }
185
186 TreeNode* TreeNodeManipulator::Copy(const TreeNode& tree, int& numberNodes, int& numberChars)
187 {
188   TreeNode* root = NewTreeNode();
189
190   ShallowCopy(&tree, root);
191
192   if(tree.mName)
193   {
194     numberChars += std::strlen(tree.mName) + 1;
195   }
196
197   if(TreeNode::STRING == tree.mType)
198   {
199     numberChars += std::strlen(tree.mStringValue) + 1;
200   }
201
202   ++numberNodes;
203
204   CopyChildren(&tree, root, numberNodes, numberChars);
205
206   return root;
207 }
208
209 void TreeNodeManipulator::CopyChildren(const TreeNode* from, TreeNode* to, int& numberNodes, int& numberChars)
210 {
211   DALI_ASSERT_DEBUG(from && "Operation on NULL JSON node");
212   DALI_ASSERT_DEBUG(to);
213
214   for( TreeNode::ConstIterator iter = from->CBegin(); iter != from->CEnd(); ++iter)
215   {
216     const TreeNode* child = &((*iter).second);
217     if(child->mName)
218     {
219       numberChars += std::strlen(child->mName) + 1;
220     }
221
222     if(TreeNode::STRING == child->mType)
223     {
224       numberChars += std::strlen(child->mStringValue) + 1;
225     }
226
227     TreeNode* newNode = NewTreeNode();
228
229     ShallowCopy(child, newNode);
230
231     TreeNodeManipulator modify(to);
232
233     modify.AddChild(newNode);
234
235     ++numberNodes;
236
237     CopyChildren(child, newNode, numberNodes, numberChars);
238   }
239 }
240
241 TreeNode *TreeNodeManipulator::AddChild(TreeNode *rhs)
242 {
243   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
244
245   rhs->mParent = mNode;
246   if (mNode->mLastChild)
247   {
248     mNode->mLastChild = mNode->mLastChild->mNextSibling = rhs;
249   }
250   else
251   {
252     mNode->mFirstChild = mNode->mLastChild = rhs;
253   }
254   return rhs;
255 }
256
257 TreeNode::NodeType TreeNodeManipulator::GetType() const
258 {
259   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
260
261   return mNode->GetType();
262 }
263
264 size_t TreeNodeManipulator::Size() const
265 {
266   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
267
268   return mNode->Size();
269 }
270
271 void TreeNodeManipulator::SetType( TreeNode::NodeType type)
272 {
273   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
274
275   if( mNode->mType != type )
276   {
277     mNode->mType = type;
278
279     if( NULL != mNode->mFirstChild )
280     {
281       // value types have no children
282       bool removeChildren = ! (TreeNode::OBJECT == type || TreeNode::ARRAY == type);
283
284       // ie if swapping array for object
285       removeChildren = (removeChildren == true) ? true : type != mNode->mType;
286
287       // so remove any children
288       if( removeChildren && NULL != mNode->mFirstChild)
289       {
290         RemoveChildren();
291       }
292     }
293   }
294 }
295
296 void TreeNodeManipulator::SetName( const char* name )
297 {
298   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
299   mNode->mName = name;
300 }
301
302 void TreeNodeManipulator::SetSubstitution( bool b )
303 {
304   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
305   mNode->mSubstituion = b;
306 }
307
308 TreeNode* TreeNodeManipulator::GetParent() const
309 {
310   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
311   return NULL == mNode ? NULL : mNode->mParent;
312 }
313
314 const TreeNode* TreeNodeManipulator::GetChild(const std::string& name) const
315 {
316   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
317   return NULL == mNode ? NULL : mNode->GetChild(name);
318 }
319
320 void TreeNodeManipulator::SetString( const char* string )
321 {
322   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
323   SetType(TreeNode::STRING);
324   mNode->mStringValue = string;
325 }
326
327 void TreeNodeManipulator::SetInteger( int i )
328 {
329   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
330   SetType(TreeNode::INTEGER);
331   mNode->mIntValue = i;
332 }
333
334 void TreeNodeManipulator::SetFloat( float f )
335 {
336   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
337   SetType(TreeNode::FLOAT);
338   mNode->mFloatValue = f;
339 }
340
341 void TreeNodeManipulator::SetBoolean( bool b )
342 {
343   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
344   SetType(TreeNode::BOOLEAN);
345   mNode->mIntValue = b == true ? 1 : 0;
346 }
347
348 void TreeNodeManipulator::Write(std::ostream& output, int indent) const
349 {
350   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
351   DoWrite(mNode, output, 0, indent, false);
352 }
353
354 void TreeNodeManipulator::DoWrite(const TreeNode *value, std::ostream& output, int level, int indentWidth, bool groupChildren) const
355 {
356   DALI_ASSERT_DEBUG(value && "Operation on NULL JSON node");
357
358   if(!groupChildren)
359   {
360     Indent(output, level, indentWidth);
361   }
362
363   if (value->GetName())
364   {
365     output << "\"" << value->GetName() << "\":";
366   }
367
368   switch(value->GetType())
369   {
370     case TreeNode::IS_NULL:
371     {
372       output << "null";
373       if(NULL != value->mNextSibling)
374       {
375         output << ", ";
376       }
377       if( !groupChildren )
378       {
379         output << std::endl;
380       }
381       break;
382     }
383     case TreeNode::OBJECT:
384     case TreeNode::ARRAY:
385     {
386       bool groupMyChildren = false;
387
388       if( TreeNode::ARRAY == value->GetType() &&
389           ( TreeNode::INTEGER == value->mFirstChild->GetType() ||
390             TreeNode::FLOAT   == value->mFirstChild->GetType() ) )
391       {
392         groupMyChildren = true;
393       }
394
395       if( value->GetType() == TreeNode::OBJECT)
396       {
397         output << std::endl;
398         Indent(output, level, indentWidth);
399         output << "{";
400       }
401       else
402       {
403         if( !groupMyChildren )
404         {
405           output << std::endl;
406           Indent(output, level, indentWidth);
407         }
408         output << "[";
409       }
410
411       if( groupMyChildren )
412       {
413         output << " ";
414       }
415       else
416       {
417         output << std::endl;
418       }
419
420       for (TreeNode::ConstIterator it = value->CBegin(); it != value->CEnd(); ++it)
421       {
422         DoWrite( &((*it).second), output, level+1, indentWidth, groupMyChildren );
423       }
424
425       if( !groupMyChildren )
426       {
427         Indent(output, level, indentWidth);
428       }
429
430       if( value->GetType() == TreeNode::OBJECT )
431       {
432         output << "}";
433       }
434       else
435       {
436         output << "]";
437       }
438
439       if( NULL != value->mNextSibling )
440       {
441         output << ",";
442       }
443
444       if( !groupChildren )
445       {
446         output << std::endl;
447       }
448
449       groupChildren = false;
450       break;
451     }
452     case TreeNode::STRING:
453     {
454       std::string escapedString = EscapeQuotes(value->GetString());
455       output << "\"" << escapedString << "\"";
456       if(NULL != value->mNextSibling)
457       {
458         output << ",";
459       }
460
461       if( groupChildren )
462       {
463         output << " ";
464       }
465       else
466       {
467         output << std::endl;
468       }
469       break;
470     }
471     case TreeNode::INTEGER:
472     {
473       output << value->GetInteger();
474       if(NULL != value->mNextSibling)
475       {
476         output << ",";
477       }
478
479       if( groupChildren )
480       {
481         output << " ";
482       }
483       else
484       {
485         output << std::endl;
486       }
487       break;
488     }
489     case TreeNode::FLOAT:
490     {
491       output.setf( std::ios::floatfield );
492       output << value->GetFloat();
493       output.unsetf( std::ios::floatfield );
494       if(NULL != value->mNextSibling)
495       {
496         output << ",";
497       }
498
499       if( groupChildren )
500       {
501         output << " ";
502       }
503       else
504       {
505         output << std::endl;
506       }
507       break;
508     }
509     case TreeNode::BOOLEAN:
510     {
511       if( value->GetInteger() )
512       {
513         output << "true";
514       }
515       else
516       {
517         output << "false";
518       }
519
520       if(NULL != value->mNextSibling)
521       {
522         output << ",";
523       }
524
525       if( groupChildren )
526       {
527         output << " ";
528       }
529       else
530       {
531         output << std::endl;
532       }
533
534       break;
535     }
536   } // switch
537 } // DoWrite
538
539
540 const TreeNode* FindIt(const std::string& childName, const TreeNode* node)
541 {
542   DALI_ASSERT_DEBUG(node);
543
544   const TreeNode* found = NULL;
545
546   if( node )
547   {
548     if( NULL != (found = node->GetChild(childName)) )
549     {
550       return found;
551     }
552     else
553     {
554       for(TreeNode::ConstIterator iter = node->CBegin(); iter != node->CEnd(); ++iter)
555       {
556         if( NULL != (found = FindIt(childName, &((*iter).second)) ) )
557         {
558           return found;
559         }
560       }
561     }
562   }
563   return found;
564 }
565
566 char *CopyString( const char *fromString, VectorCharIter& iter, const VectorCharIter& sentinel)
567 {
568   DALI_ASSERT_DEBUG(fromString);
569   DALI_ASSERT_DEBUG(iter != sentinel);
570
571   char *start= &(*iter);
572   const char *ptr = fromString;
573
574   if(ptr)
575   {
576     while(*ptr != 0)
577     {
578       DALI_ASSERT_DEBUG(iter != sentinel);
579       *iter++ = *ptr++;
580     }
581
582     *iter++ = 0;
583   }
584   return start;
585 }
586
587
588 } // namespace internal
589
590 } // namespace Toolkit
591
592 } // namespace Dali