ce17605c191b80041d642ae06c2d08776c106ad1
[platform/core/uifw/dali-adaptor-legacy.git] / dali / internal / network / common / automation.cpp
1
2 /*
3  * Copyright (c) 2018 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 <sstream>
24 #include <iomanip>
25 #include <stdio.h>
26 #include <dali/public-api/dali-core.h>
27 #include <dali/integration-api/debug.h>
28
29 using Dali::Property;
30 using Dali::Matrix;
31 using Dali::Matrix3;
32
33 namespace  // un-named namespace
34 {
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   }
56   std::string GetString() const
57   {
58     return mString;
59   }
60   float GetFloat() const
61   {
62     return atof( mString.c_str() );
63   }
64   int GetInt()
65   {
66     return atoi( mString.c_str() );
67   }
68   bool GetBoolean()
69   {
70     return (GetInt() != 0);
71   }
72
73   Dali::Vector2 GetVector2()
74   {
75     Dali::Vector2 vec2;
76
77     int count = sscanf( mString.c_str(),"%f,%f",&vec2.x,&vec2.y );
78     if( count != 2 )
79     {
80       DALI_LOG_ERROR("Bad format\n");
81     }
82     return vec2;
83   }
84
85   Dali::Vector3 GetVector3()
86   {
87     Dali::Vector3 vec3;
88
89     int count = sscanf( mString.c_str(),"%f,%f,%f",&vec3.x,&vec3.y,&vec3.z );
90     if( count != 3 )
91     {
92       DALI_LOG_ERROR("Bad format\n");
93     }
94     return vec3;
95   }
96
97   Dali::Vector4 GetVector4()
98   {
99     Dali::Vector4 vec4;
100
101     int count = sscanf( mString.c_str(),"%f,%f,%f,%f", &vec4.x, &vec4.y, &vec4.z, &vec4.w );
102     if( count != 4 )
103     {
104       DALI_LOG_ERROR("Bad format\n");
105     }
106     return vec4;
107   }
108
109 private:
110   std::string mString;
111
112 };
113
114 void SetProperty( Dali::Handle handle, int propertyId, JsonPropertyValue& propertyValue )
115 {
116   Dali::Property::Type type = handle.GetPropertyType( propertyId );
117   switch( type )
118   {
119   case Dali::Property::FLOAT:
120   {
121     float val = propertyValue.GetFloat();
122     handle.SetProperty( propertyId, Dali::Property::Value( val ) );
123     break;
124   }
125   case Dali::Property::INTEGER:
126   {
127     int val = propertyValue.GetInt();
128     handle.SetProperty( propertyId, Dali::Property::Value( val ) );
129     break;
130   }
131   case Dali::Property::BOOLEAN:
132   {
133     bool val = propertyValue.GetBoolean();
134     handle.SetProperty( propertyId, Dali::Property::Value( val ) );
135     break;
136   }
137   case Dali::Property::STRING:
138   {
139     std::string str = propertyValue.GetString();
140     handle.SetProperty( propertyId, Dali::Property::Value( str ) );
141     break;
142   }
143   case Dali::Property::VECTOR2:
144   {
145     Dali::Vector2 val = propertyValue.GetVector2();
146     handle.SetProperty( propertyId, Dali::Property::Value( val ) );
147     break;
148   }
149   case Dali::Property::VECTOR3:
150   {
151     Dali::Vector3 val = propertyValue.GetVector3();
152     handle.SetProperty( propertyId, Dali::Property::Value( val ) );
153     break;
154   }
155   case Dali::Property::VECTOR4:
156   {
157     Dali::Vector4 val = propertyValue.GetVector4();
158     handle.SetProperty( propertyId, Dali::Property::Value( val ) );
159     break;
160   }
161   default:
162   {
163     break;
164   }
165   }
166 }
167
168 int SetProperties( const std::string& setPropertyMessage )
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       Dali::Actor root = Dali::Stage::GetCurrent().GetRootLayer();
184       int id = atoi( actorId.c_str() );
185       Dali::Actor a = root.FindChildById( id );
186       if( a )
187       {
188         // lookup by name for custom properties
189         int propId = a.GetPropertyIndex( propName );
190         if( propId > 0 )
191         {
192           JsonPropertyValue pv( propValue );
193           SetProperty( a, propId, pv );
194         }
195
196       }
197     }
198   }
199
200   return 0;
201 }
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
227 }; //   un-named namespace
228
229 inline std::string Quote( const std::string& in )
230 {
231   return (std::string( "\"" ) + in + std::string( "\"" ));
232 }
233
234 template<class T>
235 std::string ToString( T i )
236 {
237   std::stringstream ss;
238   std::string s;
239   ss << i;
240   s = ss.str();
241
242   return s;
243 }
244
245 std::string GetPropertyValueString( Dali::Handle handle, int propertyIndex )
246 {
247   std::ostringstream valueStream;
248   if( propertyIndex != Dali::Property::INVALID_INDEX )
249   {
250     Dali::Property::Value value = handle.GetProperty( propertyIndex );
251
252     if( value.GetType() == Dali::Property::STRING )
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( '\x00' <= *c && *c <= '\x1f' )
271         {
272           escapedValue << "\\u" << std::hex << std::setw(4) << std::setfill('0') << int(*c);
273         }
274         else
275         {
276           escapedValue << *c;
277         }
278       }
279       valueStream << escapedValue.str();
280     }
281     else if( value.GetType() == Dali::Property::MATRIX || value.GetType() == Dali::Property::MATRIX3 )
282     {
283       MatrixToStream( value, valueStream );
284     }
285     else
286     {
287       valueStream << value;
288     }
289   }
290   else
291   {
292     valueStream << "INVALID";
293   }
294
295   return valueStream.str();
296 }
297
298 // currently rotations are output in Euler format ( may change)
299 void AppendPropertyNameAndValue( Dali::Handle handle, int propertyIndex, std::ostringstream& outputStream)
300 {
301   // get the property name and the value as a string
302   std::string propertyName( handle.GetPropertyName( propertyIndex ) );
303
304   // Apply quotes around the property name
305   outputStream << "\"" << propertyName << "\"" << ",";
306
307   // Convert value to a string
308   std::string valueString = GetPropertyValueString( handle, propertyIndex );
309
310   outputStream << "\"" << valueString << "\"";
311 }
312
313 void AppendRendererPropertyNameAndValue( Dali::Renderer renderer, int rendererIndex, const std::string& name, std::ostringstream& outputStream)
314 {
315   outputStream << ",[\"renderer[" << rendererIndex << "]." << name << "\"" << ",";
316   std::string valueString = GetPropertyValueString( renderer, renderer.GetPropertyIndex( name ) );
317   outputStream << "\"" << valueString << "\"]";
318 }
319
320 bool ExcludeProperty( int propIndex )
321 {
322   return (propIndex == Dali::Actor::Property::NAME    ||
323
324       // all of these are repeat properties of values in vectors....
325       // We don't really need these in the UI
326       propIndex == Dali::Actor::Property::ANCHOR_POINT_X || propIndex == Dali::Actor::Property::ANCHOR_POINT_Y || propIndex == Dali::Actor::Property::ANCHOR_POINT_Z || propIndex == Dali::Actor::Property::PARENT_ORIGIN_X
327       || propIndex == Dali::Actor::Property::PARENT_ORIGIN_Y || propIndex == Dali::Actor::Property::PARENT_ORIGIN_Z || propIndex == Dali::Actor::Property::COLOR_RED || propIndex == Dali::Actor::Property::COLOR_GREEN
328       || propIndex == Dali::Actor::Property::COLOR_BLUE || propIndex == Dali::Actor::Property::COLOR_ALPHA|| propIndex == Dali::Actor::Property::POSITION_X || propIndex == Dali::Actor::Property::POSITION_Y
329       || propIndex == Dali::Actor::Property::POSITION_Z|| propIndex == Dali::Actor::Property::SIZE_WIDTH|| propIndex == Dali::Actor::Property::SIZE_HEIGHT || propIndex == Dali::Actor::Property::SCALE_X || propIndex == Dali::Actor::Property::SCALE_Y
330       || propIndex == Dali::Actor::Property::SCALE_Z || propIndex == Dali::Actor::Property::SIZE_DEPTH);
331 }
332
333 std::string DumpJson( Dali::Actor actor, int level )
334 {
335   // All the information about this actor
336   std::ostringstream msg;
337   msg << "{ " << Quote( "Name" ) << " : " << Quote( actor.GetName() ) << ", " << Quote( "level" ) << " : " << level << ", " << Quote( "id" ) << " : " << actor.GetId() << ", " << Quote( "IsVisible" )
338       << " : " << actor.IsVisible() << ", " << Quote( "IsSensitive" ) << " : " << actor.IsSensitive();
339
340   msg << ", " << Quote( "properties" ) << ": [ ";
341
342   Dali::Property::IndexContainer indices;
343   actor.GetPropertyIndices( indices );
344
345   Dali::Property::IndexContainer::Iterator iter = indices.Begin();
346   int numCustom = 0;
347   for( ; iter != indices.End() ; iter++ )
348   {
349     int i = *iter;
350     if( !ExcludeProperty( i ) )
351     {
352       if( numCustom++ != 0 )
353       {
354         msg << ", ";
355       }
356       msg << "[";
357
358       AppendPropertyNameAndValue( actor, i,msg );
359
360       msg << "]";
361     }
362   }
363   if( actor.GetRendererCount() > 0 )
364   {
365     for( unsigned int i=0; i<actor.GetRendererCount(); ++i )
366     {
367       auto renderer = actor.GetRendererAt( i );
368       AppendRendererPropertyNameAndValue( renderer, i, "offset", msg );
369       AppendRendererPropertyNameAndValue( renderer, i, "size", msg );
370       AppendRendererPropertyNameAndValue( renderer, i, "offsetSizeMode", msg );
371       AppendRendererPropertyNameAndValue( renderer, i, "origin", msg );
372       AppendRendererPropertyNameAndValue( renderer, i, "anchorPoint", msg );
373     }
374   }
375
376   msg << "]";
377   msg << ", " << Quote( "children" ) << " : [ ";
378
379   // Recursively dump all the children as well
380   for( unsigned int i = 0 ; i < actor.GetChildCount() ; ++i )
381   {
382     if( i )
383     {
384       msg << " , ";
385     }
386     msg << DumpJson( actor.GetChildAt( i ), level + 1 );
387   }
388   msg << "] }";
389
390   return msg.str();
391 }
392
393 std::string GetActorTree()
394 {
395   Dali::Actor actor = Dali::Stage::GetCurrent().GetRootLayer();
396   std::string str = DumpJson( actor, 0 );
397   return str;
398 }
399
400
401
402 namespace Dali
403 {
404
405 namespace Internal
406 {
407
408 namespace Adaptor
409 {
410
411 namespace Automation
412 {
413
414 void SetProperty( const std::string& message )
415 {
416   // check the set property length is within range
417   if( message.length() > MAX_SET_PROPERTY_STRING_LENGTH )
418   {
419     DALI_LOG_ERROR("SetProperty message length too long, size = %ul\n", message.length());
420     return;
421   }
422
423   SetProperties( message );
424 }
425
426 void DumpScene( unsigned int clientId, ClientSendDataInterface* sendData )
427 {
428   char buf[32];
429   std::string json = GetActorTree();
430   int length = json.length();
431   snprintf( buf, 32, "%d\n", length );
432   std::string header( buf );
433   json = buf + json;
434   sendData->SendData( json.c_str(), json.length(), clientId );
435 }
436
437 } // namespace Automation
438
439 } // namespace Internal
440
441 } // namespace Adaptor
442
443 } // namespace Dali