57be231c242189fac6f7fdf3cafd7541ec868eba
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / styling / style-manager-impl.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 // CLASS HEADER
18 #include "style-manager-impl.h"
19
20 // INTERNAL INCLUDES
21 #include <dali-toolkit/public-api/controls/control.h>
22 #include <dali-toolkit/public-api/controls/control-impl.h>
23 #include <dali-toolkit/public-api/styling/style-manager.h>
24 #include <dali-toolkit/internal/styling/util.h>
25 #include <dali/integration-api/debug.h>
26
27 // EXTERNAL INCLUDES
28 #include <fstream>
29 #include <iostream>
30 #include <sstream>
31
32
33 namespace
34 {
35
36 const char* LANDSCAPE_QUALIFIER = "landscape";
37 const char* PORTRAIT_QUALIFIER  = "portrait";
38
39 const char* DEFAULT_THEME = DALI_STYLE_DIR "tizen-default-theme.json";
40
41 const char* PACKAGE_PATH_KEY = "PACKAGE_PATH";
42 const char* DEFAULT_PACKAGE_PATH = DALI_DATA_READ_ONLY_DIR "/toolkit/";
43
44 } // namespace
45
46 namespace Dali
47 {
48
49 namespace Toolkit
50 {
51
52 namespace Internal
53 {
54
55 namespace
56 {
57
58 BaseHandle Create()
59 {
60   BaseHandle handle = StyleManager::Get();
61
62   if ( !handle )
63   {
64     SingletonService singletonService( SingletonService::Get() );
65     if ( singletonService )
66     {
67       Toolkit::StyleManager manager = Toolkit::StyleManager( new Internal::StyleManager() );
68       singletonService.Register( typeid( manager ), manager );
69       handle = manager;
70     }
71   }
72
73   return handle;
74 }
75 TypeRegistration STYLE_MANAGER_TYPE( typeid(Dali::Toolkit::StyleManager), typeid(Dali::BaseHandle), Create, true /* Create instance at startup */ );
76
77 /**
78  * Merge two maps into one
79  */
80 void MergeMaps( const PropertyValueMap& a, const PropertyValueMap& b, PropertyValueMap& out )
81 {
82   out = a;
83   for( PropertyValueMap::const_iterator it = b.begin(), itEnd = b.end(); it != itEnd; ++it )
84   {
85     out[ it->first ] = it->second;
86   }
87 }
88
89 } // namespace
90
91 Toolkit::StyleManager StyleManager::Get()
92 {
93   Toolkit::StyleManager manager;
94
95   SingletonService singletonService( SingletonService::Get() );
96   if ( singletonService )
97   {
98     // Check whether the style manager is already created
99     Dali::BaseHandle handle = singletonService.GetSingleton( typeid( Toolkit::StyleManager ) );
100     if( handle )
101     {
102       // If so, downcast the handle of singleton
103       manager = Toolkit::StyleManager( dynamic_cast< StyleManager* >( handle.GetObjectPtr() ) );
104     }
105   }
106
107   return manager;
108 }
109
110 StyleManager::StyleManager()
111   : mOrientationDegrees( 0 ),  // Portrait
112     mSetThemeConnection( false )
113 {
114   // Add theme builder constants
115   mThemeBuilderConstants[ PACKAGE_PATH_KEY ] = DEFAULT_PACKAGE_PATH;
116
117   RequestDefaultTheme();
118
119   if( Adaptor::IsAvailable() )
120   {
121     StyleMonitor::Get().StyleChangeSignal().Connect( this, &StyleManager::StyleMonitorChange );
122   }
123 }
124
125 StyleManager::~StyleManager()
126 {
127   // Disconnect from signal
128   SetOrientation( Orientation() );
129 }
130
131 void StyleManager::SetOrientationValue( int orientation )
132 {
133   mOrientationDegrees = orientation;
134
135   Util::ConnectEventProcessingFinishedSignal();
136   mSetThemeConnection = true;
137 }
138
139 int StyleManager::GetOrientationValue()
140 {
141   return mOrientationDegrees;
142 }
143
144 void StyleManager::SetOrientation( Orientation orientation )
145 {
146   if( mOrientation )
147   {
148     mOrientation.ChangedSignal().Disconnect( this, &StyleManager::OnOrientationChanged );
149   }
150
151   OnOrientationChanged( orientation );
152
153   if( mOrientation )
154   {
155     mOrientation.ChangedSignal().Connect( this, &StyleManager::OnOrientationChanged );
156   }
157 }
158
159 Orientation StyleManager::GetOrientation()
160 {
161   return mOrientation;
162 }
163
164 void StyleManager::SetStyleConstant( const std::string& key, const Property::Value& value )
165 {
166   mStyleBuilderConstants[ key ] = value;
167 }
168
169 bool StyleManager::GetStyleConstant( const std::string& key, Property::Value& valueOut )
170 {
171   Toolkit::PropertyValueMap::iterator valueIt = mStyleBuilderConstants.find( key );
172   if( valueIt != mStyleBuilderConstants.end() )
173   {
174     valueOut = valueIt->second;
175     return true;
176   }
177
178   return false;
179 }
180
181 void StyleManager::OnOrientationChanged( Orientation orientation )
182 {
183   mOrientation = orientation;
184
185   if( mOrientation )
186   {
187     Util::ConnectEventProcessingFinishedSignal();
188     mSetThemeConnection = true;
189   }
190 }
191
192 Toolkit::Builder StyleManager::CreateBuilder( const PropertyValueMap& constants )
193 {
194   Toolkit::Builder builder = Toolkit::Builder::New();
195   builder.AddConstants( constants );
196
197   return builder;
198 }
199
200 bool StyleManager::LoadJSON( Toolkit::Builder builder, const std::string& jsonFilePath )
201 {
202   std::string fileString;
203   if( LoadFile( jsonFilePath, fileString ) )
204   {
205     builder.LoadFromString( fileString );
206     return true;
207   }
208   else
209   {
210     DALI_LOG_WARNING("Error loading file '%s'\n", jsonFilePath.c_str());
211     return false;
212   }
213 }
214
215 void StyleManager::CollectQualifiers( StringList& qualifiersOut )
216 {
217   // Append the relevant qualifier for orientation
218   int orientation = mOrientationDegrees;
219
220   if( mOrientation )
221   {
222     orientation = mOrientation.GetDegrees();
223   }
224
225   switch( orientation )
226   {
227     case 90:
228     case 270:
229     {
230       qualifiersOut.push_back( std::string( LANDSCAPE_QUALIFIER ) );
231       break;
232     }
233     case 180:
234     case 0: // fall through
235     default:
236     {
237       qualifiersOut.push_back( std::string( PORTRAIT_QUALIFIER ) );
238       break;
239     }
240   }
241 }
242
243 void StyleManager::BuildQualifiedStyleName( const std::string& styleName, const StringList& qualifiers, std::string& qualifiedStyleOut )
244 {
245   qualifiedStyleOut.append( styleName );
246
247   for( StringList::const_iterator it = qualifiers.begin(), itEnd = qualifiers.end(); it != itEnd; ++it )
248   {
249     const std::string& str = *it;
250
251     qualifiedStyleOut.append( "-" );
252     qualifiedStyleOut.append( str );
253   }
254 }
255
256 void StyleManager::ApplyStyle( Toolkit::Builder builder, Toolkit::Control control )
257 {
258   // Convert control name to lower case
259   std::string styleName = control.GetTypeName();
260   std::transform( styleName.begin(), styleName.end(), styleName.begin(), ::tolower );
261
262   // Apply the style after choosing the correct actual style (e.g. landscape or portrait)
263   StringList qualifiers;
264   CollectQualifiers( qualifiers );
265
266   while( true )
267   {
268     std::string qualifiedStyleName;
269     BuildQualifiedStyleName( styleName, qualifiers, qualifiedStyleName );
270
271     // Break if style found or we have tried the root style name (qualifiers is empty)
272     if( builder.ApplyStyle( qualifiedStyleName, control ) || qualifiers.size() == 0 )
273     {
274       break;
275     }
276
277     // Remove the last qualifier in an attempt to find a style that is valid
278     qualifiers.pop_back();
279   }
280 }
281
282 void StyleManager::ApplyThemeStyle( Toolkit::Control control )
283 {
284   if( mThemeBuilder )
285   {
286     ApplyStyle( mThemeBuilder, control );
287   }
288 }
289
290 void StyleManager::ApplyStyle( Toolkit::Control control, const std::string& jsonFileName, const std::string& styleName )
291 {
292   bool builderReady = false;
293
294   // First look in the cache
295   Toolkit::Builder builder = FindCachedBuilder( jsonFileName );
296   if( builder )
297   {
298     builderReady = true;
299   }
300   else
301   {
302     // Merge theme and style constants
303     PropertyValueMap constants;
304     MergeMaps( mThemeBuilderConstants, mStyleBuilderConstants, constants );
305
306     // Create it
307     builder = CreateBuilder( constants );
308
309     if( LoadJSON( builder, jsonFileName ) )
310     {
311       CacheBuilder( builder, jsonFileName );
312       builderReady = true;
313     }
314   }
315
316   // Apply the style to the control
317   if( builderReady )
318   {
319     builder.ApplyStyle( styleName, control );
320   }
321 }
322
323 bool StyleManager::LoadFile( const std::string& filename, std::string& stringOut )
324 {
325   DALI_ASSERT_DEBUG( 0 != filename.length());
326
327   std::ifstream in( filename.c_str(), std::ios::in );
328   if( in )
329   {
330     std::stringstream buffer;
331     buffer << in.rdbuf();
332
333     stringOut = buffer.str();
334
335     in.close();
336
337     return true;
338   }
339
340   return false;
341 }
342
343 Toolkit::StyleManager::StyleChangeSignalType& StyleManager::StyleChangeSignal()
344 {
345   return mStyleChangeSignal;
346 }
347
348 void StyleManager::RequestThemeChange( const std::string& themeFile )
349 {
350   mThemeFile = themeFile;
351
352   Util::ConnectEventProcessingFinishedSignal();
353   mSetThemeConnection = true;
354 }
355
356 void StyleManager::RequestDefaultTheme()
357 {
358   RequestThemeChange( DEFAULT_THEME );
359 }
360
361 bool StyleManager::IsThemeRequestPending()
362 {
363   return mSetThemeConnection;
364 }
365
366 void StyleManager::SetTheme()
367 {
368   mThemeBuilder = CreateBuilder( mThemeBuilderConstants );
369   LoadJSON( mThemeBuilder, mThemeFile );
370
371   mSetThemeConnection = false;
372
373   StyleChange change;
374   change.themeChange = true;
375   mStyleChangeSignal.Emit( Toolkit::StyleManager::Get(), change );
376 }
377
378 Toolkit::Builder StyleManager::FindCachedBuilder( const std::string& key )
379 {
380   BuilderMap::iterator builderIt = mBuilderCache.find( key );
381   if( builderIt != mBuilderCache.end() )
382   {
383     return builderIt->second;
384   }
385
386   return Toolkit::Builder();
387 }
388
389 void StyleManager::CacheBuilder( Toolkit::Builder builder, const std::string& key )
390 {
391   mBuilderCache[ key ] = builder;
392 }
393
394 void StyleManager::StyleMonitorChange( StyleMonitor styleMonitor, StyleChange styleChange )
395 {
396   mStyleChangeSignal.Emit( Toolkit::StyleManager::Get(), styleChange );
397 }
398
399 } // namespace Internal
400
401 } // namespace Toolkit
402
403 } // namespace Dali