066623224e560a6d357d7bc42e86ccca4d45fcf0
[platform/core/uifw/dali-adaptor.git] / dali / internal / network / common / automation.cpp
1
2 /*
3  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 // CLASS HEADER
20 #include <dali/internal/network/common/automation.h>
21
22 // EXTERNAL INCLUDES
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/dali-core.h>
25 #include <stdio.h>
26 #include <iomanip>
27 #include <sstream>
28
29 using Dali::Matrix;
30 using Dali::Matrix3;
31 using Dali::Property;
32
33 namespace // un-named namespace
34 {
35 const unsigned int MAX_SET_PROPERTY_STRING_LENGTH = 256; ///< maximum length of a set property command
36
37 class JsonPropertyValue
38 {
39 public:
40   JsonPropertyValue(const std::string& str)
41   {
42     std::size_t strLength = str.length();
43
44     mString.reserve(strLength);
45     for(std::size_t i = 0; i < strLength; ++i)
46     {
47       const char c = str[i];
48       if((c != '[') && c != ']')
49       {
50         mString.push_back(c);
51       }
52     }
53   }
54   std::string GetString() const
55   {
56     return mString;
57   }
58   float GetFloat() const
59   {
60     return atof(mString.c_str());
61   }
62   int GetInt()
63   {
64     return atoi(mString.c_str());
65   }
66   bool GetBoolean()
67   {
68     return (GetInt() != 0);
69   }
70
71   Dali::Vector2 GetVector2()
72   {
73     Dali::Vector2 vec2;
74
75     int count = sscanf(mString.c_str(), "%f,%f", &vec2.x, &vec2.y);
76     if(count != 2)
77     {
78       DALI_LOG_ERROR("Bad format\n");
79     }
80     return vec2;
81   }
82
83   Dali::Vector3 GetVector3()
84   {
85     Dali::Vector3 vec3;
86
87     int count = sscanf(mString.c_str(), "%f,%f,%f", &vec3.x, &vec3.y, &vec3.z);
88     if(count != 3)
89     {
90       DALI_LOG_ERROR("Bad format\n");
91     }
92     return vec3;
93   }
94
95   Dali::Vector4 GetVector4()
96   {
97     Dali::Vector4 vec4;
98
99     int count = sscanf(mString.c_str(), "%f,%f,%f,%f", &vec4.x, &vec4.y, &vec4.z, &vec4.w);
100     if(count != 4)
101     {
102       DALI_LOG_ERROR("Bad format\n");
103     }
104     return vec4;
105   }
106
107 private:
108   std::string mString;
109 };
110
111 void SetProperty(Dali::Handle handle, int propertyId, JsonPropertyValue& propertyValue)
112 {
113   Dali::Property::Type type = handle.GetPropertyType(propertyId);
114   switch(type)
115   {
116     case Dali::Property::FLOAT:
117     {
118       float val = propertyValue.GetFloat();
119       handle.SetProperty(propertyId, Dali::Property::Value(val));
120       break;
121     }
122     case Dali::Property::INTEGER:
123     {
124       int val = propertyValue.GetInt();
125       handle.SetProperty(propertyId, Dali::Property::Value(val));
126       break;
127     }
128     case Dali::Property::BOOLEAN:
129     {
130       bool val = propertyValue.GetBoolean();
131       handle.SetProperty(propertyId, Dali::Property::Value(val));
132       break;
133     }
134     case Dali::Property::STRING:
135     {
136       std::string str = propertyValue.GetString();
137       handle.SetProperty(propertyId, Dali::Property::Value(str));
138       break;
139     }
140     case Dali::Property::VECTOR2:
141     {
142       Dali::Vector2 val = propertyValue.GetVector2();
143       handle.SetProperty(propertyId, Dali::Property::Value(val));
144       break;
145     }
146     case Dali::Property::VECTOR3:
147     {
148       Dali::Vector3 val = propertyValue.GetVector3();
149       handle.SetProperty(propertyId, Dali::Property::Value(val));
150       break;
151     }
152     case Dali::Property::VECTOR4:
153     {
154       Dali::Vector4 val = propertyValue.GetVector4();
155       handle.SetProperty(propertyId, Dali::Property::Value(val));
156       break;
157     }
158     default:
159     {
160       break;
161     }
162   }
163 }
164
165 int SetProperties(const std::string& setPropertyMessage)
166 {
167   std::istringstream iss(setPropertyMessage);
168   std::string        token;
169   getline(iss, token, '|'); // swallow command name
170   while(getline(iss, token, '|'))
171   {
172     std::string actorId, propName, propValue;
173     if(token.compare("---") != 0)
174     {
175       std::istringstream propss(token);
176       getline(propss, actorId, ';');
177       getline(propss, propName, ';');
178       getline(propss, propValue);
179
180       Dali::Actor root = Dali::Stage::GetCurrent().GetRootLayer();
181       int         id   = atoi(actorId.c_str());
182       Dali::Actor a    = root.FindChildById(id);
183       if(a)
184       {
185         // lookup by name for custom properties
186         int propId = a.GetPropertyIndex(propName);
187         if(propId > 0)
188         {
189           JsonPropertyValue pv(propValue);
190           SetProperty(a, propId, pv);
191         }
192       }
193     }
194   }
195
196   return 0;
197 }
198
199 void MatrixToStream(Property::Value value, std::ostream& o)
200 {
201   Matrix  m4(false);
202   Matrix3 m3;
203
204   if(value.Get(m4))
205   {
206     float* matrix = m4.AsFloat();
207     o << "[ [" << matrix[0] << ", " << matrix[1] << ", " << matrix[2] << ", " << matrix[3] << "], "
208       << "[" << matrix[4] << ", " << matrix[5] << ", " << matrix[6] << ", " << matrix[7] << "], "
209       << "[" << matrix[8] << ", " << matrix[9] << ", " << matrix[10] << ", " << matrix[11] << "], "
210       << "[" << matrix[12] << ", " << matrix[13] << ", " << matrix[14] << ", " << matrix[15] << "] ]";
211   }
212   else if(value.Get(m3))
213   {
214     float* matrix = m3.AsFloat();
215     o << "[ [" << matrix[0] << ", " << matrix[1] << ", " << matrix[2] << "], "
216       << "[" << matrix[3] << ", " << matrix[4] << ", " << matrix[5] << "], "
217       << "[" << matrix[6] << ", " << matrix[7] << ", " << matrix[8] << "] ]";
218   }
219 }
220
221 }; // namespace
222
223 inline std::string Quote(const std::string& in)
224 {
225   return (std::string("\"") + in + std::string("\""));
226 }
227
228 template<class T>
229 std::string ToString(T i)
230 {
231   std::stringstream ss;
232   std::string       s;
233   ss << i;
234   s = ss.str();
235
236   return s;
237 }
238
239 std::string GetPropertyValueString(Dali::Handle handle, int propertyIndex)
240 {
241   std::ostringstream valueStream;
242   if(propertyIndex != Dali::Property::INVALID_INDEX)
243   {
244     Dali::Property::Value value = handle.GetProperty(propertyIndex);
245
246     if(value.GetType() == Dali::Property::STRING)
247     {
248       // Escape the string (to ensure valid json)
249       // Write out quotes, escapes and control characters using unicode syntax \uXXXX
250       std::ostringstream unescapedValue;
251       unescapedValue << value;
252       std::string        valueString = unescapedValue.str();
253       std::ostringstream escapedValue;
254       for(std::string::iterator c = valueString.begin(); c != valueString.end(); ++c)
255       {
256         if(*c == '"')
257         {
258           escapedValue << "\\\"";
259         }
260         else if(*c == '\\')
261         {
262           escapedValue << "\\\\";
263         }
264         else if('\x00' <= *c && *c <= '\x1f')
265         {
266           escapedValue << "\\u" << std::hex << std::setw(4) << std::setfill('0') << int(*c);
267         }
268         else
269         {
270           escapedValue << *c;
271         }
272       }
273       valueStream << escapedValue.str();
274     }
275     else if(value.GetType() == Dali::Property::MATRIX || value.GetType() == Dali::Property::MATRIX3)
276     {
277       MatrixToStream(value, valueStream);
278     }
279     else
280     {
281       valueStream << value;
282     }
283   }
284   else
285   {
286     valueStream << "INVALID";
287   }
288
289   return valueStream.str();
290 }
291
292 // currently rotations are output in Euler format ( may change)
293 void AppendPropertyNameAndValue(Dali::Handle handle, int propertyIndex, std::ostringstream& outputStream)
294 {
295   // get the property name and the value as a string
296   std::string propertyName(handle.GetPropertyName(propertyIndex));
297
298   // Apply quotes around the property name
299   outputStream << "\"" << propertyName << "\""
300                << ",";
301
302   // Convert value to a string
303   std::string valueString = GetPropertyValueString(handle, propertyIndex);
304
305   outputStream << "\"" << valueString << "\"";
306 }
307
308 void AppendRendererPropertyNameAndValue(Dali::Renderer renderer, int rendererIndex, const std::string& name, std::ostringstream& outputStream)
309 {
310   outputStream << ",[\"renderer[" << rendererIndex << "]." << name << "\""
311                << ",";
312   std::string valueString = GetPropertyValueString(renderer, renderer.GetPropertyIndex(name));
313   outputStream << "\"" << valueString << "\"]";
314 }
315
316 bool ExcludeProperty(int propIndex)
317 {
318   // all of these are repeat properties of values in vectors....
319   // We don't really need these in the UI
320   return (propIndex == Dali::Actor::Property::NAME ||
321           propIndex == Dali::Actor::Property::ANCHOR_POINT_X ||
322           propIndex == Dali::Actor::Property::ANCHOR_POINT_Y ||
323           propIndex == Dali::Actor::Property::ANCHOR_POINT_Z ||
324           propIndex == Dali::Actor::Property::PARENT_ORIGIN_X ||
325           propIndex == Dali::Actor::Property::PARENT_ORIGIN_Y ||
326           propIndex == Dali::Actor::Property::PARENT_ORIGIN_Z ||
327           propIndex == Dali::Actor::Property::COLOR_RED ||
328           propIndex == Dali::Actor::Property::COLOR_GREEN ||
329           propIndex == Dali::Actor::Property::COLOR_BLUE ||
330           propIndex == Dali::Actor::Property::COLOR_ALPHA ||
331           propIndex == Dali::Actor::Property::POSITION_X ||
332           propIndex == Dali::Actor::Property::POSITION_Y ||
333           propIndex == Dali::Actor::Property::POSITION_Z ||
334           propIndex == Dali::Actor::Property::SIZE_WIDTH ||
335           propIndex == Dali::Actor::Property::SIZE_HEIGHT ||
336           propIndex == Dali::Actor::Property::SCALE_X ||
337           propIndex == Dali::Actor::Property::SCALE_Y ||
338           propIndex == Dali::Actor::Property::SCALE_Z ||
339           propIndex == Dali::Actor::Property::SIZE_DEPTH);
340 }
341
342 std::string DumpJson(Dali::Actor actor, int level)
343 {
344   // All the information about this actor
345   std::ostringstream msg;
346   msg << "{ " << Quote("Name") << " : " << Quote(actor.GetProperty<std::string>(Actor::Property::NAME)) << ", " << Quote("level") << " : " << level << ", " << Quote("id") << " : " << actor.GetId() << ", " << Quote("IsVisible")
347       << " : " << actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE) << ", " << Quote("IsSensitive") << " : " << actor.GetProperty<bool>(Actor::Property::SENSITIVE);
348
349   msg << ", " << Quote("properties") << ": [ ";
350
351   Dali::Property::IndexContainer indices;
352   actor.GetPropertyIndices(indices);
353
354   Dali::Property::IndexContainer::Iterator iter      = indices.Begin();
355   int                                      numCustom = 0;
356   for(; iter != indices.End(); iter++)
357   {
358     int i = *iter;
359     if(!ExcludeProperty(i))
360     {
361       if(numCustom++ != 0)
362       {
363         msg << ", ";
364       }
365       msg << "[";
366
367       AppendPropertyNameAndValue(actor, i, msg);
368
369       msg << "]";
370     }
371   }
372   if(actor.GetRendererCount() > 0)
373   {
374     for(unsigned int i = 0; i < actor.GetRendererCount(); ++i)
375     {
376       auto renderer = actor.GetRendererAt(i);
377       AppendRendererPropertyNameAndValue(renderer, i, "offset", msg);
378       AppendRendererPropertyNameAndValue(renderer, i, "size", msg);
379       AppendRendererPropertyNameAndValue(renderer, i, "offsetSizeMode", msg);
380       AppendRendererPropertyNameAndValue(renderer, i, "origin", msg);
381       AppendRendererPropertyNameAndValue(renderer, i, "anchorPoint", msg);
382     }
383   }
384
385   msg << "]";
386   msg << ", " << Quote("children") << " : [ ";
387
388   // Recursively dump all the children as well
389   for(unsigned int i = 0; i < actor.GetChildCount(); ++i)
390   {
391     if(i)
392     {
393       msg << " , ";
394     }
395     msg << DumpJson(actor.GetChildAt(i), level + 1);
396   }
397   msg << "] }";
398
399   return msg.str();
400 }
401
402 std::string GetActorTree()
403 {
404   Dali::Actor actor = Dali::Stage::GetCurrent().GetRootLayer();
405   std::string str   = DumpJson(actor, 0);
406   return str;
407 }
408
409 namespace Dali
410 {
411 namespace Internal
412 {
413 namespace Adaptor
414 {
415 namespace Automation
416 {
417 void SetProperty(const std::string& message)
418 {
419   // check the set property length is within range
420   if(message.length() > MAX_SET_PROPERTY_STRING_LENGTH)
421   {
422     DALI_LOG_ERROR("SetProperty message length too long, size = %ul\n", message.length());
423     return;
424   }
425
426   SetProperties(message);
427 }
428
429 void DumpScene(unsigned int clientId, ClientSendDataInterface* sendData)
430 {
431   char        buf[32];
432   std::string json   = GetActorTree();
433   int         length = json.length();
434   snprintf(buf, 32, "%d\n", length);
435   std::string header(buf);
436   json = buf + json;
437   sendData->SendData(json.c_str(), json.length(), clientId);
438 }
439
440 } // namespace Automation
441
442 } // namespace Adaptor
443
444 } // namespace Internal
445
446 } // namespace Dali