Merge "Updated patch coverage script." into devel/master
[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   else if( TreeNode::ARRAY == mNode->mType )
295   {
296     if( mNode->mFirstChild != NULL )
297     {
298       TreeNode::NodeType type = mNode->mFirstChild->GetType();
299
300       if( TreeNode::FLOAT == type || TreeNode::INTEGER == type )
301       {
302         // Arrays of numbers should be replaced, not appended to.
303         RemoveChildren();
304       }
305     }
306   }
307 }
308
309 void TreeNodeManipulator::SetName( const char* name )
310 {
311   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
312   mNode->mName = name;
313 }
314
315 void TreeNodeManipulator::SetSubstitution( bool b )
316 {
317   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
318   mNode->mSubstituion = b;
319 }
320
321 TreeNode* TreeNodeManipulator::GetParent() const
322 {
323   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
324   return NULL == mNode ? NULL : mNode->mParent;
325 }
326
327 const TreeNode* TreeNodeManipulator::GetChild(const std::string& name) const
328 {
329   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
330   return NULL == mNode ? NULL : mNode->GetChild(name);
331 }
332
333 void TreeNodeManipulator::SetString( const char* string )
334 {
335   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
336   SetType(TreeNode::STRING);
337   mNode->mStringValue = string;
338 }
339
340 void TreeNodeManipulator::SetInteger( int i )
341 {
342   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
343   SetType(TreeNode::INTEGER);
344   mNode->mIntValue = i;
345 }
346
347 void TreeNodeManipulator::SetFloat( float f )
348 {
349   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
350   SetType(TreeNode::FLOAT);
351   mNode->mFloatValue = f;
352 }
353
354 void TreeNodeManipulator::SetBoolean( bool b )
355 {
356   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
357   SetType(TreeNode::BOOLEAN);
358   mNode->mIntValue = b == true ? 1 : 0;
359 }
360
361 void TreeNodeManipulator::Write(std::ostream& output, int indent) const
362 {
363   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
364   DoWrite(mNode, output, 0, indent, false);
365 }
366
367 void TreeNodeManipulator::DoWrite(const TreeNode *value, std::ostream& output, int level, int indentWidth, bool groupChildren) const
368 {
369   DALI_ASSERT_DEBUG(value && "Operation on NULL JSON node");
370
371   if(!groupChildren)
372   {
373     Indent(output, level, indentWidth);
374   }
375
376   if (value->GetName())
377   {
378     output << "\"" << value->GetName() << "\":";
379   }
380
381   switch(value->GetType())
382   {
383     case TreeNode::IS_NULL:
384     {
385       output << "null";
386       if(NULL != value->mNextSibling)
387       {
388         output << ", ";
389       }
390       if( !groupChildren )
391       {
392         output << std::endl;
393       }
394       break;
395     }
396     case TreeNode::OBJECT:
397     case TreeNode::ARRAY:
398     {
399       bool groupMyChildren = false;
400
401       if( TreeNode::ARRAY == value->GetType() && value->mFirstChild &&
402           ( TreeNode::INTEGER == value->mFirstChild->GetType() ||
403             TreeNode::FLOAT   == value->mFirstChild->GetType() ) )
404       {
405         groupMyChildren = true;
406       }
407
408       if( value->GetType() == TreeNode::OBJECT)
409       {
410         output << std::endl;
411         Indent(output, level, indentWidth);
412         output << "{";
413       }
414       else
415       {
416         if( !groupMyChildren )
417         {
418           output << std::endl;
419           Indent(output, level, indentWidth);
420         }
421         output << "[";
422       }
423
424       if( groupMyChildren )
425       {
426         output << " ";
427       }
428       else
429       {
430         output << std::endl;
431       }
432
433       for (TreeNode::ConstIterator it = value->CBegin(); it != value->CEnd(); ++it)
434       {
435         DoWrite( &((*it).second), output, level+1, indentWidth, groupMyChildren );
436       }
437
438       if( !groupMyChildren )
439       {
440         Indent(output, level, indentWidth);
441       }
442
443       if( value->GetType() == TreeNode::OBJECT )
444       {
445         output << "}";
446       }
447       else
448       {
449         output << "]";
450       }
451
452       if( NULL != value->mNextSibling )
453       {
454         output << ",";
455       }
456
457       if( !groupChildren )
458       {
459         output << std::endl;
460       }
461
462       groupChildren = false;
463       break;
464     }
465     case TreeNode::STRING:
466     {
467       std::string escapedString = EscapeQuotes(value->GetString());
468       output << "\"" << escapedString << "\"";
469       if(NULL != value->mNextSibling)
470       {
471         output << ",";
472       }
473
474       if( groupChildren )
475       {
476         output << " ";
477       }
478       else
479       {
480         output << std::endl;
481       }
482       break;
483     }
484     case TreeNode::INTEGER:
485     {
486       output << value->GetInteger();
487       if(NULL != value->mNextSibling)
488       {
489         output << ",";
490       }
491
492       if( groupChildren )
493       {
494         output << " ";
495       }
496       else
497       {
498         output << std::endl;
499       }
500       break;
501     }
502     case TreeNode::FLOAT:
503     {
504       output.setf( std::ios::floatfield );
505       output << value->GetFloat();
506       output.unsetf( std::ios::floatfield );
507       if(NULL != value->mNextSibling)
508       {
509         output << ",";
510       }
511
512       if( groupChildren )
513       {
514         output << " ";
515       }
516       else
517       {
518         output << std::endl;
519       }
520       break;
521     }
522     case TreeNode::BOOLEAN:
523     {
524       if( value->GetInteger() )
525       {
526         output << "true";
527       }
528       else
529       {
530         output << "false";
531       }
532
533       if(NULL != value->mNextSibling)
534       {
535         output << ",";
536       }
537
538       if( groupChildren )
539       {
540         output << " ";
541       }
542       else
543       {
544         output << std::endl;
545       }
546
547       break;
548     }
549   } // switch
550 } // DoWrite
551
552 const TreeNode* FindIt(std::string_view childName, const TreeNode* node)
553 {
554   DALI_ASSERT_DEBUG(node);
555
556   const TreeNode* found = NULL;
557
558   if( node )
559   {
560     if( NULL != (found = node->GetChild(childName)) )
561     {
562       return found;
563     }
564     else
565     {
566       for(TreeNode::ConstIterator iter = node->CBegin(); iter != node->CEnd(); ++iter)
567       {
568         if( NULL != (found = FindIt(childName, &((*iter).second)) ) )
569         {
570           return found;
571         }
572       }
573     }
574   }
575   return found;
576 }
577
578 char *CopyString( const char *fromString, VectorCharIter& iter, const VectorCharIter& sentinel)
579 {
580   DALI_ASSERT_DEBUG(fromString);
581   DALI_ASSERT_DEBUG(iter != sentinel);
582
583   char *start= &(*iter);
584   const char *ptr = fromString;
585
586   if(ptr)
587   {
588     while(*ptr != 0)
589     {
590       DALI_ASSERT_DEBUG(iter != sentinel);
591       *iter++ = *ptr++;
592     }
593
594     *iter++ = 0;
595   }
596   return start;
597 }
598
599
600 } // namespace internal
601
602 } // namespace Toolkit
603
604 } // namespace Dali