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