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