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