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