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