[release] version bump to 13.0 beta1
[vuplus_xbmc] / xbmc / settings / lib / SettingsManager.cpp
1 /*
2  *      Copyright (C) 2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "SettingsManager.h"
22 #include "SettingDefinitions.h"
23 #include "SettingSection.h"
24 #include "Setting.h"
25 #include "utils/log.h"
26 #include "utils/StringUtils.h"
27 #include "utils/XBMCTinyXML.h"
28
29
30 CSettingsManager::CSettingsManager()
31   : m_initialized(false), m_loaded(false)
32 { }
33
34 CSettingsManager::~CSettingsManager()
35 {
36   // first clear all registered settings handler and subsettings
37   // implementations because we can't be sure that they are still valid
38   m_settingsHandlers.clear();
39   m_subSettings.clear();
40   m_settingCreators.clear();
41   m_settingControlCreators.clear();
42
43   Clear();
44 }
45
46 bool CSettingsManager::Initialize(const TiXmlElement *root)
47 {
48   CExclusiveLock lock(m_critical);
49   CExclusiveLock settingsLock(m_settingsCritical);
50   if (m_initialized || root == NULL)
51     return false;
52
53   if (!StringUtils::EqualsNoCase(root->ValueStr(), SETTING_XML_ROOT))
54   {
55     CLog::Log(LOGERROR, "CSettingsManager: error reading settings definition: doesn't contain <settings> tag");
56     return false;
57   }
58
59   const TiXmlNode *sectionNode = root->FirstChild(SETTING_XML_ELM_SECTION);
60   while (sectionNode != NULL)
61   {
62     std::string sectionId;
63     if (CSettingSection::DeserializeIdentification(sectionNode, sectionId))
64     {
65       CSettingSection *section = NULL;
66       SettingSectionMap::iterator itSection = m_sections.find(sectionId);
67       bool update = (itSection != m_sections.end());
68       if (!update)
69         section = new CSettingSection(sectionId, this);
70       else
71         section = itSection->second;
72
73       if (section->Deserialize(sectionNode, update))
74       {
75         section->CheckRequirements();
76         if (!update)
77           m_sections[section->GetId()] = section;
78
79         // get all settings and add them to the settings map
80         for (SettingCategoryList::const_iterator categoryIt = section->GetCategories().begin(); categoryIt != section->GetCategories().end(); ++categoryIt)
81         {
82           (*categoryIt)->CheckRequirements();
83           for (SettingGroupList::const_iterator groupIt = (*categoryIt)->GetGroups().begin(); groupIt != (*categoryIt)->GetGroups().end(); ++groupIt)
84           {
85             (*groupIt)->CheckRequirements();
86             for (SettingList::const_iterator settingIt = (*groupIt)->GetSettings().begin(); settingIt != (*groupIt)->GetSettings().end(); ++settingIt)
87             {
88               (*settingIt)->CheckRequirements();
89
90               const std::string &settingId = (*settingIt)->GetId();
91               SettingMap::iterator setting = m_settings.find(settingId);
92               if (setting == m_settings.end())
93               {
94                 Setting tmpSetting = { NULL };
95                 std::pair<SettingMap::iterator, bool> tmpIt = m_settings.insert(make_pair(settingId, tmpSetting));
96                 setting = tmpIt.first;
97               }
98                 
99               if (setting->second.setting == NULL)
100               {
101                 setting->second.setting = *settingIt;
102                 (*settingIt)->m_callback = this;
103               }
104             }
105           }
106         }
107       }
108       else
109       {
110         CLog::Log(LOGWARNING, "CSettingsManager: unable to read section \"%s\"", sectionId.c_str());
111         if (!update)
112           delete section;
113       }
114     }
115       
116     sectionNode = sectionNode->NextSibling(SETTING_XML_ELM_SECTION);
117   }
118
119   for (SettingMap::iterator itSettingDep = m_settings.begin(); itSettingDep != m_settings.end(); ++itSettingDep)
120   {
121     if (itSettingDep->second.setting == NULL)
122       continue;
123
124     const SettingDependencies& deps = itSettingDep->second.setting->GetDependencies();
125     for (SettingDependencies::const_iterator depIt = deps.begin(); depIt != deps.end(); ++depIt)
126     {
127       std::set<std::string> settingIds = depIt->GetSettings();
128       for (std::set<std::string>::const_iterator itSettingId = settingIds.begin(); itSettingId != settingIds.end(); ++itSettingId)
129       {
130         SettingMap::iterator setting = m_settings.find(*itSettingId);
131         if (setting == m_settings.end())
132           continue;
133
134         bool newDep = true;
135         SettingDependencies &settingDeps = setting->second.dependencies[itSettingDep->first];
136         for (SettingDependencies::const_iterator itDeps = settingDeps.begin(); itDeps != settingDeps.end(); ++itDeps)
137         {
138           if (itDeps->GetType() == depIt->GetType())
139           {
140             newDep = false;
141             break;
142           }
143         }
144
145         if (newDep)
146           settingDeps.push_back(*depIt);
147       }
148     }
149   }
150
151   return true;
152 }
153
154 bool CSettingsManager::Load(const TiXmlElement *root, bool &updated, bool triggerEvents /* = true */, std::map<std::string, CSetting*> *loadedSettings /* = NULL */)
155 {
156   CSharedLock lock(m_critical);
157   CExclusiveLock settingsLock(m_settingsCritical);
158   if (m_loaded || root == NULL)
159     return false;
160
161   if (triggerEvents && !OnSettingsLoading())
162     return false;
163
164   if (!Deserialize(root, loadedSettings))
165     return false;
166
167   bool ret = true;
168   // load any ISubSettings implementations
169   if (triggerEvents)
170     ret = Load(root);
171
172   updated = UpdateSettings(root);
173
174   if (triggerEvents)
175     OnSettingsLoaded();
176
177   return ret;
178 }
179
180 bool CSettingsManager::Save(TiXmlNode *root) const
181 {
182   CSharedLock lock(m_critical);
183   CSharedLock settingsLock(m_settingsCritical);
184   if (!m_initialized || root == NULL)
185     return false;
186
187   if (!OnSettingsSaving())
188     return false;
189
190   if (!Serialize(root))
191   {
192     CLog::Log(LOGERROR, "CSettingsManager: failed to save settings");
193     return false;
194   }
195
196   // save any ISubSettings implementations
197   for (std::set<ISubSettings*>::const_iterator it = m_subSettings.begin(); it != m_subSettings.end(); ++it)
198   {
199     if (!(*it)->Save(root))
200       return false;
201   }
202
203   OnSettingsSaved();
204
205   return true;
206 }
207
208 void CSettingsManager::Unload()
209 {
210   CExclusiveLock lock(m_settingsCritical);
211   if (!m_loaded)
212     return;
213
214   // needs to be set before calling CSetting::Reset() to avoid calls to
215   // OnSettingChanging() and OnSettingChanged()
216   m_loaded = false;
217
218   for (SettingMap::iterator setting = m_settings.begin(); setting != m_settings.end(); ++setting)
219     setting->second.setting->Reset();
220
221   OnSettingsUnloaded();
222 }
223
224 void CSettingsManager::Clear()
225 {
226   CExclusiveLock lock(m_critical);
227   Unload();
228
229   m_settings.clear();
230   for (SettingSectionMap::iterator section = m_sections.begin(); section != m_sections.end(); ++section)
231     delete section->second;
232   m_sections.clear();
233
234   OnSettingsCleared();
235
236   for (std::set<ISubSettings*>::const_iterator it = m_subSettings.begin(); it != m_subSettings.end(); ++it)
237     (*it)->Clear();
238
239   m_initialized = false;
240 }
241
242 bool CSettingsManager::LoadSetting(const TiXmlNode *node, const std::string &settingId)
243 {
244   if (node == NULL)
245     return false;
246
247   CSetting *setting = GetSetting(settingId);
248   if (setting == NULL)
249     return false;
250
251   return LoadSetting(node, setting);
252 }
253
254 void CSettingsManager::SetInitialized()
255 {
256   CExclusiveLock lock(m_settingsCritical);
257   if (m_initialized)
258     return;
259
260   m_initialized = true;
261
262   for (SettingMap::iterator setting = m_settings.begin(); setting != m_settings.end(); )
263   {
264     SettingMap::iterator tmpIterator = setting++;
265     if (tmpIterator->second.setting == NULL)
266       m_settings.erase(tmpIterator);
267   }
268 }
269
270 void CSettingsManager::RegisterCallback(ISettingCallback *callback, const std::set<std::string> &settingList)
271 {
272   CExclusiveLock lock(m_settingsCritical);
273   if (callback == NULL)
274     return;
275
276   for (std::set<std::string>::const_iterator settingIt = settingList.begin(); settingIt != settingList.end(); ++settingIt)
277   {
278     std::string id = *settingIt;
279     StringUtils::ToLower(id);
280
281     SettingMap::iterator setting = m_settings.find(id);
282     if (setting == m_settings.end())
283     {
284       if (m_initialized)
285         continue;
286
287       Setting tmpSetting = { NULL };
288       std::pair<SettingMap::iterator, bool> tmpIt = m_settings.insert(make_pair(id, tmpSetting));
289       setting = tmpIt.first;
290     }
291
292     setting->second.callbacks.insert(callback);
293   }
294 }
295
296 void CSettingsManager::UnregisterCallback(ISettingCallback *callback)
297 {
298   CExclusiveLock lock(m_settingsCritical);
299   for (SettingMap::iterator settingIt = m_settings.begin(); settingIt != m_settings.end(); ++settingIt)
300     settingIt->second.callbacks.erase(callback);
301 }
302
303 void CSettingsManager::RegisterSettingType(const std::string &settingType, ISettingCreator *settingCreator)
304 {
305   CExclusiveLock lock(m_critical);
306   if (settingType.empty() || settingCreator == NULL)
307     return;
308
309   SettingCreatorMap::const_iterator creatorIt = m_settingCreators.find(settingType);
310   if (creatorIt == m_settingCreators.end())
311     m_settingCreators.insert(make_pair(settingType, settingCreator));
312 }
313
314 void CSettingsManager::RegisterSettingControl(const std::string &controlType, ISettingControlCreator *settingControlCreator)
315 {
316   if (controlType.empty() || settingControlCreator == NULL)
317     return;
318
319   CExclusiveLock lock(m_critical);
320   SettingControlCreatorMap::const_iterator creatorIt = m_settingControlCreators.find(controlType);
321   if (creatorIt == m_settingControlCreators.end())
322     m_settingControlCreators.insert(make_pair(controlType, settingControlCreator));
323 }
324
325 void CSettingsManager::RegisterSettingsHandler(ISettingsHandler *settingsHandler)
326 {
327   if (settingsHandler == NULL)
328     return;
329
330   CExclusiveLock lock(m_critical);
331   if (find(m_settingsHandlers.begin(), m_settingsHandlers.end(), settingsHandler) == m_settingsHandlers.end())
332     m_settingsHandlers.push_back(settingsHandler);
333 }
334
335 void CSettingsManager::UnregisterSettingsHandler(ISettingsHandler *settingsHandler)
336 {
337   if (settingsHandler == NULL)
338     return;
339
340   CExclusiveLock lock(m_critical);
341   SettingsHandlers::iterator it = find(m_settingsHandlers.begin(), m_settingsHandlers.end(), settingsHandler);
342   if (it != m_settingsHandlers.end())
343     m_settingsHandlers.erase(it);
344 }
345
346 void CSettingsManager::RegisterSubSettings(ISubSettings *subSettings)
347 {
348   CExclusiveLock lock(m_critical);
349   if (subSettings == NULL)
350     return;
351
352   m_subSettings.insert(subSettings);
353 }
354
355 void CSettingsManager::UnregisterSubSettings(ISubSettings *subSettings)
356 {
357   CExclusiveLock lock(m_critical);
358   if (subSettings == NULL)
359     return;
360
361   m_subSettings.erase(subSettings);
362 }
363
364 void CSettingsManager::RegisterSettingOptionsFiller(const std::string &identifier, IntegerSettingOptionsFiller optionsFiller)
365 {
366   if (identifier.empty() || optionsFiller == NULL)
367     return;
368
369   RegisterSettingOptionsFiller(identifier, (void*)optionsFiller, SettingOptionsFillerTypeInteger);
370 }
371
372 void CSettingsManager::RegisterSettingOptionsFiller(const std::string &identifier, StringSettingOptionsFiller optionsFiller)
373 {
374   if (identifier.empty() || optionsFiller == NULL)
375     return;
376
377   RegisterSettingOptionsFiller(identifier, (void*)optionsFiller, SettingOptionsFillerTypeString);
378 }
379
380 void CSettingsManager::UnregisterSettingOptionsFiller(const std::string &identifier)
381 {
382   CExclusiveLock lock(m_critical);
383   m_optionsFillers.erase(identifier);
384 }
385
386 void* CSettingsManager::GetSettingOptionsFiller(const CSetting *setting)
387 {
388   CSharedLock lock(m_critical);
389   if (setting == NULL)
390     return NULL;
391
392   // get the option filler's identifier
393   std::string filler;
394   if (setting->GetType() == SettingTypeInteger)
395     filler = ((const CSettingInt*)setting)->GetOptionsFiller();
396   else if (setting->GetType() == SettingTypeString)
397     filler = ((const CSettingString*)setting)->GetOptionsFiller();
398
399   if (filler.empty())
400     return NULL;
401
402   // check if such an option filler is known
403   SettingOptionsFillerMap::const_iterator fillerIt = m_optionsFillers.find(filler);
404   if (fillerIt == m_optionsFillers.end())
405     return NULL;
406
407   if (fillerIt->second.filler == NULL)
408     return NULL;
409
410   // make sure the option filler's type matches the setting's type
411   switch (fillerIt->second.type)
412   {
413     case SettingOptionsFillerTypeInteger:
414     {
415       if (setting->GetType() != SettingTypeInteger)
416         return NULL;
417
418       break;
419     }
420     
421     case SettingOptionsFillerTypeString:
422     {
423       if (setting->GetType() != SettingTypeString)
424         return NULL;
425
426       break;
427     }
428
429     default:
430       return NULL;
431   }
432
433   return fillerIt->second.filler;
434 }
435
436 CSetting* CSettingsManager::GetSetting(const std::string &id) const
437 {
438   CSharedLock lock(m_settingsCritical);
439   if (id.empty())
440     return NULL;
441
442   std::string settingId = id;
443   StringUtils::ToLower(settingId);
444
445   SettingMap::const_iterator setting = m_settings.find(settingId);
446   if (setting != m_settings.end())
447     return setting->second.setting;
448
449   CLog::Log(LOGDEBUG, "CSettingsManager: requested setting (%s) was not found.", id.c_str());
450   return NULL;
451 }
452
453 std::vector<CSettingSection*> CSettingsManager::GetSections() const
454 {
455   CSharedLock lock(m_critical);
456   std::vector<CSettingSection*> sections;
457   for (SettingSectionMap::const_iterator sectionIt = m_sections.begin(); sectionIt != m_sections.end(); ++sectionIt)
458     sections.push_back(sectionIt->second);
459
460   return sections;
461 }
462
463 CSettingSection* CSettingsManager::GetSection(const std::string &section) const
464 {
465   CSharedLock lock(m_critical);
466   if (section.empty())
467     return NULL;
468
469   std::string sectionId = section;
470   StringUtils::ToLower(sectionId);
471
472   SettingSectionMap::const_iterator sectionIt = m_sections.find(sectionId);
473   if (sectionIt != m_sections.end())
474     return sectionIt->second;
475
476   CLog::Log(LOGDEBUG, "CSettingsManager: requested setting section (%s) was not found.", section.c_str());
477   return NULL;
478 }
479
480 SettingDependencyMap CSettingsManager::GetDependencies(const std::string &id) const
481 {
482   CSharedLock lock(m_settingsCritical);
483   SettingMap::const_iterator setting = m_settings.find(id);
484   if (setting == m_settings.end())
485     return SettingDependencyMap();
486
487   return setting->second.dependencies;
488 }
489
490 SettingDependencyMap CSettingsManager::GetDependencies(const CSetting *setting) const
491 {
492   if (setting == NULL)
493     return SettingDependencyMap();
494
495   return GetDependencies(setting->GetId());
496 }
497
498 bool CSettingsManager::GetBool(const std::string &id) const
499 {
500   CSharedLock lock(m_settingsCritical);
501   CSetting *setting = GetSetting(id);
502   if (setting == NULL || setting->GetType() != SettingTypeBool)
503     return false;
504
505   return ((CSettingBool*)setting)->GetValue();
506 }
507
508 bool CSettingsManager::SetBool(const std::string &id, bool value)
509 {
510   CSharedLock lock(m_settingsCritical);
511   CSetting *setting = GetSetting(id);
512   if (setting == NULL || setting->GetType() != SettingTypeBool)
513     return false;
514
515   return ((CSettingBool*)setting)->SetValue(value);
516 }
517
518 bool CSettingsManager::ToggleBool(const std::string &id)
519 {
520   CSharedLock lock(m_settingsCritical);
521   CSetting *setting = GetSetting(id);
522   if (setting == NULL || setting->GetType() != SettingTypeBool)
523     return false;
524
525   return SetBool(id, !((CSettingBool*)setting)->GetValue());
526 }
527
528 int CSettingsManager::GetInt(const std::string &id) const
529 {
530   CSharedLock lock(m_settingsCritical);
531   CSetting *setting = GetSetting(id);
532   if (setting == NULL || setting->GetType() != SettingTypeInteger)
533     return 0;
534
535   return ((CSettingInt*)setting)->GetValue();
536 }
537
538 bool CSettingsManager::SetInt(const std::string &id, int value)
539 {
540   CSharedLock lock(m_settingsCritical);
541   CSetting *setting = GetSetting(id);
542   if (setting == NULL || setting->GetType() != SettingTypeInteger)
543     return false;
544
545   return ((CSettingInt*)setting)->SetValue(value);
546 }
547
548 double CSettingsManager::GetNumber(const std::string &id) const
549 {
550   CSharedLock lock(m_settingsCritical);
551   CSetting *setting = GetSetting(id);
552   if (setting == NULL || setting->GetType() != SettingTypeNumber)
553     return 0.0;
554
555   return ((CSettingNumber*)setting)->GetValue();
556 }
557
558 bool CSettingsManager::SetNumber(const std::string &id, double value)
559 {
560   CSharedLock lock(m_settingsCritical);
561   CSetting *setting = GetSetting(id);
562   if (setting == NULL || setting->GetType() != SettingTypeNumber)
563     return false;
564
565   return ((CSettingNumber*)setting)->SetValue(value);
566 }
567
568 std::string CSettingsManager::GetString(const std::string &id) const
569 {
570   CSharedLock lock(m_settingsCritical);
571   CSetting *setting = GetSetting(id);
572   if (setting == NULL || setting->GetType() != SettingTypeString)
573     return "";
574
575   return ((CSettingString*)setting)->GetValue();
576 }
577
578 bool CSettingsManager::SetString(const std::string &id, const std::string &value)
579 {
580   CSharedLock lock(m_settingsCritical);
581   CSetting *setting = GetSetting(id);
582   if (setting == NULL || setting->GetType() != SettingTypeString)
583     return false;
584
585   return ((CSettingString*)setting)->SetValue(value);
586 }
587
588 std::vector< boost::shared_ptr<CSetting> > CSettingsManager::GetList(const std::string &id) const
589 {
590   CSharedLock lock(m_settingsCritical);
591   CSetting *setting = GetSetting(id);
592   if (setting == NULL || setting->GetType() != SettingTypeList)
593     return std::vector< boost::shared_ptr<CSetting> >();
594
595   return ((CSettingList*)setting)->GetValue();
596 }
597
598 bool CSettingsManager::SetList(const std::string &id, const std::vector< boost::shared_ptr<CSetting> > &value)
599 {
600   CSharedLock lock(m_settingsCritical);
601   CSetting *setting = GetSetting(id);
602   if (setting == NULL || setting->GetType() != SettingTypeList)
603     return false;
604
605   return ((CSettingList*)setting)->SetValue(value);
606 }
607
608 void CSettingsManager::AddCondition(const std::string &condition)
609 {
610   CExclusiveLock lock(m_critical);
611   if (condition.empty())
612     return;
613
614   m_conditions.AddCondition(condition);
615 }
616
617 void CSettingsManager::AddCondition(const std::string &identifier, SettingConditionCheck condition)
618 {
619   CExclusiveLock lock(m_critical);
620   if (identifier.empty() || condition == NULL)
621     return;
622
623   m_conditions.AddCondition(identifier, condition);
624 }
625   
626 bool CSettingsManager::Serialize(TiXmlNode *parent) const
627 {
628   if (parent == NULL)
629     return false;
630
631   CSharedLock lock(m_settingsCritical);
632
633   for (SettingMap::const_iterator it = m_settings.begin(); it != m_settings.end(); ++it)
634   {
635     if (it->second.setting->GetType() == SettingTypeAction)
636       continue;
637
638     std::vector<std::string> parts = StringUtils::Split(it->first, ".");
639     if (parts.size() != 2 || parts.at(0).empty() || parts.at(1).empty())
640     {
641       CLog::Log(LOGWARNING, "CSettingsManager: unable to save setting \"%s\"", it->first.c_str());
642       continue;
643     }
644       
645     TiXmlNode *sectionNode = parent->FirstChild(parts.at(0));
646     if (sectionNode == NULL)
647     {
648       TiXmlElement sectionElement(parts.at(0));
649       sectionNode = parent->InsertEndChild(sectionElement);
650         
651       if (sectionNode == NULL)
652       {
653         CLog::Log(LOGWARNING, "CSettingsManager: unable to write <%s> tag", parts.at(0).c_str());
654         continue;
655       }
656     }
657       
658     TiXmlElement settingElement(parts.at(1));
659     TiXmlNode *settingNode = sectionNode->InsertEndChild(settingElement);
660     if (settingNode == NULL)
661     {
662       CLog::Log(LOGWARNING, "CSetting: unable to write <%s> tag in <%s>", parts.at(1).c_str(), parts.at(0).c_str());
663       continue;
664     }
665       
666     TiXmlText value(it->second.setting->ToString());
667     settingNode->InsertEndChild(value);
668   }
669
670   return true;
671 }
672   
673 bool CSettingsManager::Deserialize(const TiXmlNode *node, std::map<std::string, CSetting*> *loadedSettings /* = NULL */)
674 {
675   if (node == NULL)
676     return false;
677
678   CSharedLock lock(m_settingsCritical);
679
680   for (SettingMap::iterator it = m_settings.begin(); it != m_settings.end(); ++it)
681   {
682     if (LoadSetting(node, it->second.setting) && loadedSettings != NULL)
683       loadedSettings->insert(make_pair(it->first, it->second.setting));
684   }
685
686   return true;
687 }
688
689 bool CSettingsManager::OnSettingChanging(const CSetting *setting)
690 {
691   if (setting == NULL)
692     return false;
693
694   CSharedLock lock(m_settingsCritical);
695   if (!m_loaded)
696     return true;
697
698   SettingMap::const_iterator settingIt = m_settings.find(setting->GetId());
699   if (settingIt == m_settings.end())
700     return false;
701
702   Setting settingData = settingIt->second;
703   // now that we have a copy of the setting's data, we can leave the lock
704   lock.Leave();
705
706   for (CallbackSet::iterator callback = settingData.callbacks.begin();
707         callback != settingData.callbacks.end();
708         ++callback)
709   {
710     if (!(*callback)->OnSettingChanging(setting))
711       return false;
712   }
713
714   return true;
715 }
716   
717 void CSettingsManager::OnSettingChanged(const CSetting *setting)
718 {
719   CSharedLock lock(m_settingsCritical);
720   if (!m_loaded || setting == NULL)
721     return;
722     
723   SettingMap::const_iterator settingIt = m_settings.find(setting->GetId());
724   if (settingIt == m_settings.end())
725     return;
726
727   Setting settingData = settingIt->second;
728   // now that we have a copy of the setting's data, we can leave the lock
729   lock.Leave();
730     
731   for (CallbackSet::iterator callback = settingData.callbacks.begin();
732         callback != settingData.callbacks.end();
733         ++callback)
734     (*callback)->OnSettingChanged(setting);
735
736   // now handle any settings which depend on the changed setting
737   const SettingDependencyMap& deps = GetDependencies(setting);
738   for (SettingDependencyMap::const_iterator depsIt = deps.begin(); depsIt != deps.end(); ++depsIt)
739   {
740     for (SettingDependencies::const_iterator depIt = depsIt->second.begin(); depIt != depsIt->second.end(); ++depIt)
741       UpdateSettingByDependency(depsIt->first, *depIt);
742   }
743 }
744
745 void CSettingsManager::OnSettingAction(const CSetting *setting)
746 {
747   CSharedLock lock(m_settingsCritical);
748   if (!m_loaded || setting == NULL)
749     return;
750
751   SettingMap::const_iterator settingIt = m_settings.find(setting->GetId());
752   if (settingIt == m_settings.end())
753     return;
754
755   Setting settingData = settingIt->second;
756   // now that we have a copy of the setting's data, we can leave the lock
757   lock.Leave();
758
759   for (CallbackSet::iterator callback = settingData.callbacks.begin();
760         callback != settingData.callbacks.end();
761         ++callback)
762     (*callback)->OnSettingAction(setting);
763 }
764
765 bool CSettingsManager::OnSettingUpdate(CSetting* &setting, const char *oldSettingId, const TiXmlNode *oldSettingNode)
766 {
767   CSharedLock lock(m_settingsCritical);
768   if (setting == NULL)
769     return false;
770
771   SettingMap::const_iterator settingIt = m_settings.find(setting->GetId());
772   if (settingIt == m_settings.end())
773     return false;
774
775   Setting settingData = settingIt->second;
776   // now that we have a copy of the setting's data, we can leave the lock
777   lock.Leave();
778
779   bool ret = false;
780   for (CallbackSet::iterator callback = settingData.callbacks.begin();
781         callback != settingData.callbacks.end();
782         ++callback)
783     ret |= (*callback)->OnSettingUpdate(setting, oldSettingId, oldSettingNode);
784
785   return ret;
786 }
787
788 void CSettingsManager::OnSettingPropertyChanged(const CSetting *setting, const char *propertyName)
789 {
790   CSharedLock lock(m_settingsCritical);
791   if (!m_loaded || setting == NULL)
792     return;
793
794   SettingMap::const_iterator settingIt = m_settings.find(setting->GetId());
795   if (settingIt == m_settings.end())
796     return;
797
798   Setting settingData = settingIt->second;
799   // now that we have a copy of the setting's data, we can leave the lock
800   lock.Leave();
801
802   for (CallbackSet::iterator callback = settingData.callbacks.begin();
803         callback != settingData.callbacks.end();
804         ++callback)
805     (*callback)->OnSettingPropertyChanged(setting, propertyName);
806 }
807
808 CSetting* CSettingsManager::CreateSetting(const std::string &settingType, const std::string &settingId, CSettingsManager *settingsManager /* = NULL */) const
809 {
810   if (StringUtils::EqualsNoCase(settingType, "boolean"))
811     return new CSettingBool(settingId, const_cast<CSettingsManager*>(this));
812   else if (StringUtils::EqualsNoCase(settingType, "integer"))
813     return new CSettingInt(settingId, const_cast<CSettingsManager*>(this));
814   else if (StringUtils::EqualsNoCase(settingType, "number"))
815     return new CSettingNumber(settingId, const_cast<CSettingsManager*>(this));
816   else if (StringUtils::EqualsNoCase(settingType, "string"))
817     return new CSettingString(settingId, const_cast<CSettingsManager*>(this));
818   else if (StringUtils::EqualsNoCase(settingType, "action"))
819     return new CSettingAction(settingId, const_cast<CSettingsManager*>(this));
820   else if (settingType.size() > 6 &&
821            StringUtils::StartsWith(settingType, "list[") &&
822            StringUtils::EndsWith(settingType, "]"))
823   {
824     std::string elementType = StringUtils::Mid(settingType, 5, settingType.size() - 6);
825     CSetting *elementSetting = CreateSetting(elementType, settingId + ".definition", const_cast<CSettingsManager*>(this));
826     if (elementSetting != NULL)
827       return new CSettingList(settingId, elementSetting, const_cast<CSettingsManager*>(this));
828   }
829
830   CSharedLock lock(m_critical);
831   SettingCreatorMap::const_iterator creator = m_settingCreators.find(settingType);
832   if (creator != m_settingCreators.end())
833     return creator->second->CreateSetting(settingType, settingId, (CSettingsManager*)this);
834
835   return NULL;
836 }
837
838 ISettingControl* CSettingsManager::CreateControl(const std::string &controlType) const
839 {
840   if (controlType.empty())
841     return NULL;
842
843   CSharedLock lock(m_critical);
844   SettingControlCreatorMap::const_iterator creator = m_settingControlCreators.find(controlType);
845   if (creator != m_settingControlCreators.end() && creator->second != NULL)
846     return creator->second->CreateControl(controlType);
847
848   return NULL;
849 }
850
851 bool CSettingsManager::OnSettingsLoading()
852 {
853   CSharedLock lock(m_critical);
854   for (SettingsHandlers::const_iterator it = m_settingsHandlers.begin(); it != m_settingsHandlers.end(); ++it)
855   {
856     if (!(*it)->OnSettingsLoading())
857       return false;
858   }
859
860   return true;
861 }
862
863 void CSettingsManager::OnSettingsLoaded()
864 {
865   CSharedLock lock(m_critical);
866   for (SettingsHandlers::const_iterator it = m_settingsHandlers.begin(); it != m_settingsHandlers.end(); ++it)
867     (*it)->OnSettingsLoaded();
868 }
869
870 bool CSettingsManager::OnSettingsSaving() const
871 {
872   CSharedLock lock(m_critical);
873   for (SettingsHandlers::const_iterator it = m_settingsHandlers.begin(); it != m_settingsHandlers.end(); ++it)
874   {
875     if (!(*it)->OnSettingsSaving())
876       return false;
877   }
878
879   return true;
880 }
881
882 void CSettingsManager::OnSettingsSaved() const
883 {
884   CSharedLock lock(m_critical);
885   for (SettingsHandlers::const_iterator it = m_settingsHandlers.begin(); it != m_settingsHandlers.end(); ++it)
886     (*it)->OnSettingsSaved();
887 }
888
889 void CSettingsManager::OnSettingsCleared()
890 {
891   CSharedLock lock(m_critical);
892   for (SettingsHandlers::const_iterator it = m_settingsHandlers.begin(); it != m_settingsHandlers.end(); ++it)
893     (*it)->OnSettingsCleared();
894 }
895
896 bool CSettingsManager::Load(const TiXmlNode *settings)
897 {
898   bool ok = true;
899   CSharedLock lock(m_critical);
900   for (std::set<ISubSettings*>::const_iterator it = m_subSettings.begin(); it != m_subSettings.end(); ++it)
901     ok &= (*it)->Load(settings);
902
903   return ok;
904 }
905
906 bool CSettingsManager::LoadSetting(const TiXmlNode *node, CSetting *setting)
907 {
908   if (node == NULL || setting == NULL)
909     return false;
910
911   if (setting->GetType() == SettingTypeAction)
912     return false;
913
914   const std::string &settingId = setting->GetId();
915
916   std::vector<std::string> parts = StringUtils::Split(settingId, ".");
917   if (parts.size() != 2 || parts.at(0).empty() || parts.at(1).empty())
918   {
919     CLog::Log(LOGWARNING, "CSettingsManager: unable to load setting \"%s\"", settingId.c_str());
920     return false;
921   }
922
923   const TiXmlNode *sectionNode = node->FirstChild(parts.at(0));
924   if (sectionNode == NULL)
925     return false;
926
927   const TiXmlNode *settingNode = sectionNode->FirstChild(parts.at(1));
928   if (settingNode == NULL)
929     return false;
930
931   if (!setting->FromString(settingNode->FirstChild() != NULL ? settingNode->FirstChild()->ValueStr() : StringUtils::Empty))
932   {
933     CLog::Log(LOGWARNING, "CSettingsManager: unable to read value of setting \"%s\"", settingId.c_str());
934     return false;
935   }
936
937   return true;
938 }
939
940 bool CSettingsManager::UpdateSettings(const TiXmlNode *root)
941 {
942   bool updated = false;
943   CSharedLock lock(m_settingsCritical);
944
945   for (SettingMap::iterator setting = m_settings.begin(); setting != m_settings.end(); ++setting)
946   {
947     const std::set<CSettingUpdate>& updates = setting->second.setting->GetUpdates();
948     if (updates.empty())
949       continue;
950
951     for (std::set<CSettingUpdate>::const_iterator update = updates.begin(); update != updates.end(); ++update)
952       updated |= UpdateSetting(root, setting->second.setting, *update);
953   }
954
955   return updated;
956 }
957
958 bool CSettingsManager::UpdateSetting(const TiXmlNode *node, CSetting *setting, const CSettingUpdate& update)
959 {
960   if (node == NULL || setting == NULL || update.GetType() == SettingUpdateTypeNone)
961     return false;
962
963   bool updated = false;
964   const char *oldSetting = NULL;
965   const TiXmlNode *oldSettingNode = NULL;
966   if (update.GetType() == SettingUpdateTypeRename)
967   {
968     if (update.GetValue().empty())
969       return false;
970
971     oldSetting = update.GetValue().c_str();
972     std::vector<std::string> parts = StringUtils::Split(oldSetting, ".");
973     if (parts.size() != 2 || parts.at(0).empty() || parts.at(1).empty())
974       return false;
975
976     const TiXmlNode *sectionNode = node->FirstChild(parts.at(0));
977     if (sectionNode == NULL)
978       return false;
979
980     oldSettingNode = sectionNode->FirstChild(parts.at(1));
981     if (oldSettingNode == NULL)
982       return false;
983
984     if (setting->FromString(oldSettingNode->FirstChild() != NULL ? oldSettingNode->FirstChild()->ValueStr() : StringUtils::Empty))
985       updated = true;
986     else
987       CLog::Log(LOGWARNING, "CSetting: unable to update \"%s\" through automatically renaming from \"%s\"", setting->GetId().c_str(), oldSetting);
988   }
989
990   updated |= OnSettingUpdate(setting, oldSetting, oldSettingNode);
991   return updated;
992 }
993
994 void CSettingsManager::UpdateSettingByDependency(const std::string &settingId, const CSettingDependency &dependency)
995 {
996   CSetting *setting = GetSetting(settingId);
997   if (setting == NULL)
998     return;
999
1000   switch (dependency.GetType())
1001   {
1002     case SettingDependencyTypeEnable:
1003       // just trigger the property changed callback and a call to
1004       // CSetting::IsEnabled() will automatically determine the new
1005       // enabled state
1006       OnSettingPropertyChanged(setting, "enabled");
1007       break;
1008
1009     case SettingDependencyTypeUpdate:
1010     {
1011       SettingType type = (SettingType)setting->GetType();
1012       if (type == SettingTypeInteger)
1013       {
1014         CSettingInt *settingInt = ((CSettingInt*)setting);
1015         if (settingInt->GetOptionsType() == SettingOptionsTypeDynamic)
1016           settingInt->UpdateDynamicOptions();
1017       }
1018       else if (type == SettingTypeString)
1019       {
1020         CSettingString *settingString = ((CSettingString*)setting);
1021         if (settingString->GetOptionsType() == SettingOptionsTypeDynamic)
1022           settingString->UpdateDynamicOptions();
1023       }
1024       break;
1025     }
1026
1027     case SettingDependencyTypeVisible:
1028       // just trigger the property changed callback and a call to
1029       // CSetting::IsVisible() will automatically determine the new
1030       // visible state
1031       OnSettingPropertyChanged(setting, "visible");
1032       break;
1033
1034     case SettingDependencyTypeNone:
1035     default:
1036       break;
1037   }
1038 }
1039
1040 void CSettingsManager::RegisterSettingOptionsFiller(const std::string &identifier, void *filler, SettingOptionsFillerType type)
1041 {
1042   CExclusiveLock lock(m_critical);
1043   SettingOptionsFillerMap::const_iterator it = m_optionsFillers.find(identifier);
1044   if (it != m_optionsFillers.end())
1045     return;
1046
1047   SettingOptionsFiller optionsFiller = { filler, type };
1048   m_optionsFillers.insert(make_pair(identifier, optionsFiller));
1049 }