71d8378fd261a5a313a3b26496c02d553f4b72e1
[vuplus_xbmc] / xbmc / settings / lib / Setting.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 <sstream>
22
23 #include "Setting.h"
24 #include "SettingDefinitions.h"
25 #include "SettingsManager.h"
26 #include "utils/log.h"
27 #include "utils/StringUtils.h"
28 #include "utils/XBMCTinyXML.h"
29 #include "utils/XMLUtils.h"
30
31 CSetting::CSetting(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
32   : ISetting(id, settingsManager),
33     m_callback(NULL),
34     m_label(-1), m_help(-1),
35     m_level(SettingLevelStandard),
36     m_control(NULL),
37     m_changed(false)
38 { }
39   
40 CSetting::CSetting(const std::string &id, const CSetting &setting)
41   : ISetting(id, setting.m_settingsManager),
42     m_callback(NULL),
43     m_label(-1), m_help(-1),
44     m_level(SettingLevelStandard),
45     m_control(NULL),
46     m_changed(false)
47 {
48   m_id = id;
49   Copy(setting);
50 }
51
52 CSetting::~CSetting()
53 {
54   delete m_control;
55 }
56
57 bool CSetting::Deserialize(const TiXmlNode *node, bool update /* = false */)
58 {
59   // handle <visible> conditions
60   if (!ISetting::Deserialize(node, update))
61     return false;
62
63   const TiXmlElement *element = node->ToElement();
64   if (element == NULL)
65     return false;
66
67   // get the attributes label and help
68   int tmp = -1;
69   if (element->QueryIntAttribute(SETTING_XML_ATTR_LABEL, &tmp) == TIXML_SUCCESS && tmp > 0)
70     m_label = tmp;
71   
72   tmp = -1;
73   if (element->QueryIntAttribute(SETTING_XML_ATTR_HELP, &tmp) == TIXML_SUCCESS && tmp > 0)
74     m_help = tmp;
75   const char *parentSetting = element->Attribute(SETTING_XML_ATTR_PARENT);
76   if (parentSetting != NULL)
77     m_parentSetting = parentSetting;
78
79   // get the <level>
80   int level = -1;
81   if (XMLUtils::GetInt(node, SETTING_XML_ELM_LEVEL, level))
82     m_level = (SettingLevel)level;
83     
84   if (m_level < (int)SettingLevelBasic || m_level > (int)SettingLevelInternal)
85     m_level = SettingLevelStandard;
86
87   const TiXmlNode *dependencies = node->FirstChild(SETTING_XML_ELM_DEPENDENCIES);
88   if (dependencies != NULL)
89   {
90     const TiXmlNode *dependencyNode = dependencies->FirstChild(SETTING_XML_ELM_DEPENDENCY);
91     while (dependencyNode != NULL)
92     {
93       CSettingDependency dependency(m_settingsManager);
94       if (dependency.Deserialize(dependencyNode))
95         m_dependencies.push_back(dependency);
96       else
97         CLog::Log(LOGWARNING, "CSetting: error reading <dependency> tag of \"%s\"", m_id.c_str());
98
99       dependencyNode = dependencyNode->NextSibling(SETTING_XML_ELM_DEPENDENCY);
100     }
101   }
102
103   const TiXmlElement *control = node->FirstChildElement(SETTING_XML_ELM_CONTROL);
104   if (control != NULL)
105   {
106     const char *controlType = control->Attribute(SETTING_XML_ATTR_TYPE);
107     if (controlType == NULL)
108     {
109       CLog::Log(LOGERROR, "CSetting: error reading \"type\" attribute of <control> tag of \"%s\"", m_id.c_str());
110       return false;
111     }
112
113     m_control = m_settingsManager->CreateControl(controlType);
114     if (m_control == NULL || !m_control->Deserialize(control, update))
115     {
116       CLog::Log(LOGERROR, "CSetting: error reading <control> tag of \"%s\"", m_id.c_str());
117       return false;
118     }
119   }
120   else if (!update && m_level < SettingLevelInternal)
121   {
122     CLog::Log(LOGERROR, "CSetting: missing <control> tag of \"%s\"", m_id.c_str());
123     return false;
124   }
125
126   const TiXmlNode *updates = node->FirstChild(SETTING_XML_ELM_UPDATES);
127   if (updates != NULL)
128   {
129     const TiXmlElement *updateElem = updates->FirstChildElement(SETTING_XML_ELM_UPDATE);
130     while (updateElem != NULL)
131     {
132       CSettingUpdate update;
133       if (update.Deserialize(updateElem))
134       {
135         if (!m_updates.insert(update).second)
136           CLog::Log(LOGWARNING, "CSetting: duplicate <update> definition for \"%s\"", m_id.c_str());
137       }
138       else
139         CLog::Log(LOGWARNING, "CSetting: error reading <update> tag of \"%s\"", m_id.c_str());
140
141       updateElem = updateElem->NextSiblingElement(SETTING_XML_ELM_UPDATE);
142     }
143   }
144     
145   return true;
146 }
147   
148 bool CSetting::IsEnabled() const
149 {
150   bool enabled = true;
151   for (SettingDependencies::const_iterator depIt = m_dependencies.begin(); depIt != m_dependencies.end(); ++depIt)
152   {
153     if (depIt->GetType() != SettingDependencyTypeEnable)
154       continue;
155
156     if (!depIt->Check())
157     {
158       enabled = false;
159       break;
160     }
161   }
162
163   return enabled;
164 }
165
166 bool CSetting::IsVisible() const
167 {
168   if (!ISetting::IsVisible())
169     return false;
170
171   bool visible = true;
172   for (SettingDependencies::const_iterator depIt = m_dependencies.begin(); depIt != m_dependencies.end(); ++depIt)
173   {
174     if (depIt->GetType() != SettingDependencyTypeVisible)
175       continue;
176
177     if (!depIt->Check())
178     {
179       visible = false;
180       break;
181     }
182   }
183
184   return visible;
185 }
186
187 bool CSetting::OnSettingChanging(const CSetting *setting)
188 {
189   if (m_callback == NULL)
190     return true;
191     
192   return m_callback->OnSettingChanging(setting);
193 }
194   
195 void CSetting::OnSettingChanged(const CSetting *setting)
196 {
197   if (m_callback == NULL)
198     return;
199
200   m_callback->OnSettingChanged(setting);
201 }
202
203 void CSetting::OnSettingAction(const CSetting *setting)
204 {
205   if (m_callback == NULL)
206     return;
207
208   m_callback->OnSettingAction(setting);
209 }
210
211 bool CSetting::OnSettingUpdate(CSetting* &setting, const char *oldSettingId, const TiXmlNode *oldSettingNode)
212 {
213   if (m_callback == NULL)
214     return false;
215
216   return m_callback->OnSettingUpdate(setting, oldSettingId, oldSettingNode);
217 }
218
219 void CSetting::OnSettingPropertyChanged(const CSetting *setting, const char *propertyName)
220 {
221   if (m_callback == NULL)
222     return;
223
224   m_callback->OnSettingPropertyChanged(setting, propertyName);
225 }
226
227 void CSetting::Copy(const CSetting &setting)
228 {
229   SetVisible(setting.IsVisible());
230   SetRequirementsMet(setting.MeetsRequirements());
231   m_callback = setting.m_callback;
232   m_label = setting.m_label;
233   m_help = setting.m_help;
234   m_level = setting.m_level;
235   
236   delete m_control;
237   if (setting.m_control != NULL)
238   {
239     m_control = m_settingsManager->CreateControl(setting.m_control->GetType());
240     *m_control = *setting.m_control;
241   }
242   else
243     m_control = NULL;
244
245   m_dependencies = setting.m_dependencies;
246   m_updates = setting.m_updates;
247   m_changed = setting.m_changed;
248 }
249
250 CSettingList::CSettingList(const std::string &id, CSetting *settingDefinition, CSettingsManager *settingsManager /* = NULL */)
251   : CSetting(id, settingsManager),
252     m_definition(settingDefinition),
253     m_delimiter("|"),
254     m_minimumItems(0), m_maximumItems(-1)
255 { }
256
257 CSettingList::CSettingList(const std::string &id, const CSettingList &setting)
258   : CSetting(id, setting),
259     m_definition(NULL),
260     m_delimiter("|"),
261     m_minimumItems(0), m_maximumItems(-1)
262 {
263   copy(setting);
264 }
265
266 CSettingList::~CSettingList()
267 {
268   m_values.clear();
269   m_defaults.clear();
270   delete m_definition;
271 }
272
273 CSetting* CSettingList::Clone(const std::string &id) const
274 {
275   if (m_definition == NULL)
276     return NULL;
277
278   return new CSettingList(id, *this);
279 }
280
281 bool CSettingList::Deserialize(const TiXmlNode *node, bool update /* = false */)
282 {
283   CExclusiveLock lock(m_critical);
284
285   if (m_definition == NULL)
286     return false;
287
288   if (!CSetting::Deserialize(node, update))
289     return false;
290
291   const TiXmlElement *element = node->ToElement();
292   if (element == NULL)
293   {
294     CLog::Log(LOGWARNING, "CSettingList: unable to read type of list setting of %s", m_id.c_str());
295     return false;
296   }
297
298   if (!m_definition->Deserialize(node, update))
299     return false;
300
301   const TiXmlNode *constraints = node->FirstChild(SETTING_XML_ELM_CONSTRAINTS);
302   if (constraints != NULL)
303   {
304     // read the delimiter
305     std::string delimiter;
306     if (XMLUtils::GetString(constraints, SETTING_XML_ELM_DELIMITER, delimiter) && !delimiter.empty())
307       m_delimiter = delimiter;
308
309     XMLUtils::GetInt(constraints, SETTING_XML_ELM_MINIMUM_ITEMS, m_minimumItems);
310     if (m_minimumItems < 0)
311       m_minimumItems = 0;
312     XMLUtils::GetInt(constraints, SETTING_XML_ELM_MAXIMUM_ITEMS, m_maximumItems);
313     if (m_maximumItems <= 0)
314       m_maximumItems = -1;
315     else if (m_maximumItems < m_minimumItems)
316     {
317       CLog::Log(LOGWARNING, "CSettingList: invalid <minimum> (%d) and/or <maximum> (%d) of %s", m_minimumItems, m_maximumItems, m_id.c_str());
318       return false;
319     }
320   }
321
322   // read the default and initial values
323   std::string values;
324   if (XMLUtils::GetString(node, SETTING_XML_ELM_DEFAULT, values))
325   {
326     if (!fromString(values, m_defaults))
327     {
328       CLog::Log(LOGWARNING, "CSettingList: invalid <default> definition \"%s\" of %s", values.c_str(), m_id.c_str());
329       return false;
330     }
331     Reset();
332   }
333
334   return true;
335 }
336
337 int CSettingList::GetElementType() const
338 {
339   CSharedLock lock(m_critical);
340   
341   if (m_definition == NULL)
342     return SettingTypeNone;
343
344   return m_definition->GetType();
345 }
346
347 bool CSettingList::FromString(const std::string &value)
348 {
349   SettingPtrList values;
350   if (!fromString(value, values))
351     return false;
352
353   return SetValue(values);
354 }
355
356 std::string CSettingList::ToString() const
357 {
358   return toString(m_values);
359 }
360
361 bool CSettingList::Equals(const std::string &value) const
362 {
363   SettingPtrList values;
364   if (!fromString(value, values) ||
365       values.size() != m_values.size())
366     return false;
367
368   bool ret = true;
369   for (size_t index = 0; index < values.size(); index++)
370   {
371     if (!m_values[index]->Equals(values[index]->ToString()))
372     {
373       ret = false;
374       break;
375     }
376   }
377
378   return ret;
379 }
380
381 bool CSettingList::CheckValidity(const std::string &value) const
382 {
383   SettingPtrList values;
384   return fromString(value, values);
385 }
386
387 void CSettingList::Reset()
388 {
389   CExclusiveLock lock(m_critical);
390   SettingPtrList values;
391   for (SettingPtrList::const_iterator it = m_defaults.begin(); it != m_defaults.end(); ++it)
392     values.push_back(SettingPtr((*it)->Clone((*it)->GetId())));
393
394   SetValue(values);
395 }
396
397 bool CSettingList::FromString(const std::vector<std::string> &value)
398 {
399   SettingPtrList values;
400   if (!fromValues(value, values))
401     return false;
402
403   return SetValue(values);
404 }
405
406 bool CSettingList::SetValue(const SettingPtrList &values)
407 {
408   CExclusiveLock lock(m_critical);
409
410   if ((int)values.size() < m_minimumItems ||
411      (m_maximumItems > 0 && (int)values.size() > m_maximumItems))
412     return false;
413
414   bool equal = values.size() == m_values.size();
415   for (size_t index = 0; index < values.size(); index++)
416   {
417     if (values[index]->GetType() != GetElementType())
418       return false;
419
420     if (equal &&
421         !values[index]->Equals(m_values[index]->ToString()))
422       equal = false;
423   }
424
425   if (equal)
426     return true;
427
428   SettingPtrList oldValues = m_values;
429   m_values.clear();
430   m_values.insert(m_values.begin(), values.begin(), values.end());
431
432   if (!OnSettingChanging(this))
433   {
434     m_values = oldValues;
435
436     // the setting couldn't be changed because one of the
437     // callback handlers failed the OnSettingChanging()
438     // callback so we need to let all the callback handlers
439     // know that the setting hasn't changed
440     OnSettingChanging(this);
441     return false;
442   }
443
444   m_changed = (toString(m_values) == toString(m_defaults));
445   OnSettingChanged(this);
446   return true;
447 }
448
449 void CSettingList::SetDefault(const SettingPtrList &values)
450 {
451   CExclusiveLock lock(m_critical);
452
453   m_defaults.clear();
454   m_defaults.insert(m_defaults.begin(), values.begin(), values.end());
455
456   if (!m_changed)
457   {
458     m_values.clear();
459     for (SettingPtrList::const_iterator it = m_defaults.begin(); it != m_defaults.end(); ++it)
460       m_values.push_back(SettingPtr((*it)->Clone((*it)->GetId())));
461   }
462 }
463
464 void CSettingList::copy(const CSettingList &setting)
465 {
466   CSetting::Copy(setting);
467
468   copy(setting.m_values, m_values);
469   copy(setting.m_defaults, m_defaults);
470   
471   if (setting.m_definition != NULL)
472   {
473     CSetting *definitionCopy = setting.m_definition->Clone(m_id + ".definition");
474     if (definitionCopy != NULL)
475       m_definition = definitionCopy;
476   }
477
478   m_delimiter = setting.m_delimiter;
479   m_minimumItems = setting.m_minimumItems;
480   m_maximumItems = setting.m_maximumItems;
481 }
482
483 void CSettingList::copy(const SettingPtrList &srcValues, SettingPtrList &dstValues)
484 {
485   dstValues.clear();
486
487   for (SettingPtrList::const_iterator itValue = srcValues.begin(); itValue != srcValues.end(); ++itValue)
488   {
489     if (*itValue == NULL)
490       continue;
491
492     CSetting *valueCopy = (*itValue)->Clone((*itValue)->GetId());
493     if (valueCopy == NULL)
494       continue;
495
496     dstValues.push_back(SettingPtr(valueCopy));
497   }
498 }
499
500 bool CSettingList::fromString(const std::string &strValue, SettingPtrList &values) const
501 {
502   std::vector<std::string> strValues = StringUtils::Split(strValue, m_delimiter);
503   return fromValues(strValues, values);
504 }
505
506 bool CSettingList::fromValues(const std::vector<std::string> &strValues, SettingPtrList &values) const
507 {
508   if ((int)strValues.size() < m_minimumItems ||
509      (m_maximumItems > 0 && (int)strValues.size() > m_maximumItems))
510     return false;
511
512   bool ret = true;
513   int index = 0;
514   for (std::vector<std::string>::const_iterator itValue = strValues.begin(); itValue != strValues.end(); ++itValue)
515   {
516     CSetting *settingValue = m_definition->Clone(StringUtils::Format("%s.%d", m_id.c_str(), index++));
517     if (settingValue == NULL ||
518         !settingValue->FromString(*itValue))
519     {
520       delete settingValue;
521       ret = false;
522       break;
523     }
524
525     values.push_back(SettingPtr(settingValue));
526   }
527
528   if (!ret)
529     values.clear();
530
531   return ret;
532 }
533
534 std::string CSettingList::toString(const SettingPtrList &values) const
535 {
536   std::vector<std::string> strValues;
537   for (SettingPtrList::const_iterator it = values.begin(); it != values.end(); ++it)
538   {
539     if (*it != NULL)
540       strValues.push_back((*it)->ToString());
541   }
542
543   return StringUtils::Join(strValues, m_delimiter);
544 }
545   
546 CSettingBool::CSettingBool(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
547   : CSetting(id, settingsManager),
548     m_value(false), m_default(false)
549 { }
550   
551 CSettingBool::CSettingBool(const std::string &id, const CSettingBool &setting)
552   : CSetting(id, setting)
553 {
554   copy(setting);
555 }
556
557 CSettingBool::CSettingBool(const std::string &id, int label, bool value, CSettingsManager *settingsManager /* = NULL */)
558   : CSetting(id, settingsManager),
559     m_value(value), m_default(value)
560 {
561   m_label = label;
562 }
563
564 CSetting* CSettingBool::Clone(const std::string &id) const
565 {
566   return new CSettingBool(id, *this);
567 }
568
569 bool CSettingBool::Deserialize(const TiXmlNode *node, bool update /* = false */)
570 {
571   CExclusiveLock lock(m_critical);
572
573   if (!CSetting::Deserialize(node, update))
574     return false;
575     
576   // get the default value
577   bool value;
578   if (XMLUtils::GetBoolean(node, SETTING_XML_ELM_DEFAULT, value))
579     m_value = m_default = value;
580   else if (!update)
581   {
582     CLog::Log(LOGERROR, "CSettingBool: error reading the default value of \"%s\"", m_id.c_str());
583     return false;
584   }
585
586   return true;
587 }
588   
589 bool CSettingBool::FromString(const std::string &value)
590 {
591   bool bValue;
592   if (!fromString(value, bValue))
593     return false;
594
595   return SetValue(bValue);
596 }
597
598 std::string CSettingBool::ToString() const
599 {
600   return m_value ? "true" : "false";
601 }
602
603 bool CSettingBool::Equals(const std::string &value) const
604 {
605   bool bValue;
606   return (fromString(value, bValue) && m_value == bValue);
607 }
608
609 bool CSettingBool::CheckValidity(const std::string &value) const
610 {
611   bool bValue;
612   return fromString(value, bValue);
613 }
614
615 bool CSettingBool::SetValue(bool value)
616 {
617   CExclusiveLock lock(m_critical);
618
619   if (value == m_value)
620     return true;
621
622   bool oldValue = m_value;
623   m_value = value;
624
625   if (!OnSettingChanging(this))
626   {
627     m_value = oldValue;
628
629     // the setting couldn't be changed because one of the
630     // callback handlers failed the OnSettingChanging()
631     // callback so we need to let all the callback handlers
632     // know that the setting hasn't changed
633     OnSettingChanging(this);
634     return false;
635   }
636
637   m_changed = m_value != m_default;
638   OnSettingChanged(this);
639   return true;
640 }
641   
642 void CSettingBool::SetDefault(bool value)
643 {
644   CExclusiveLock lock(m_critical);
645
646   m_default = value;
647   if (!m_changed)
648     m_value = m_default;
649 }
650
651 void CSettingBool::copy(const CSettingBool &setting)
652 {
653   CSetting::Copy(setting);
654
655   m_value = setting.m_value;
656   m_default = setting.m_default;
657 }
658   
659 bool CSettingBool::fromString(const std::string &strValue, bool &value) const
660 {
661   if (StringUtils::EqualsNoCase(strValue, "true"))
662   {
663     value = true;
664     return true;
665   }
666   if (StringUtils::EqualsNoCase(strValue, "false"))
667   {
668     value = false;
669     return true;
670   }
671
672   return false;
673 }
674
675 CSettingInt::CSettingInt(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
676   : CSetting(id, settingsManager),
677     m_value(0), m_default(0),
678     m_min(0), m_step(1), m_max(0)
679 { }
680   
681 CSettingInt::CSettingInt(const std::string &id, const CSettingInt &setting)
682   : CSetting(id, setting)
683 {
684   copy(setting);
685 }
686
687 CSettingInt::CSettingInt(const std::string &id, int label, int value, int minimum, int step, int maximum, CSettingsManager *settingsManager /* = NULL */)
688   : CSetting(id, settingsManager),
689     m_value(value), m_default(value),
690     m_min(minimum), m_step(step), m_max(maximum)
691 {
692   m_label = label;
693 }
694
695 CSettingInt::CSettingInt(const std::string &id, int label, int value, const StaticIntegerSettingOptions &options, CSettingsManager *settingsManager /* = NULL */)
696   : CSetting(id, settingsManager),
697     m_value(value), m_default(value),
698     m_min(0), m_step(1), m_max(0),
699     m_options(options)
700 {
701   m_label = label;
702 }
703
704 CSetting* CSettingInt::Clone(const std::string &id) const
705 {
706   return new CSettingInt(id, *this);
707 }
708
709 bool CSettingInt::Deserialize(const TiXmlNode *node, bool update /* = false */)
710 {
711   CExclusiveLock lock(m_critical);
712
713   if (!CSetting::Deserialize(node, update))
714     return false;
715
716   // get the default value
717   int value;
718   if (XMLUtils::GetInt(node, SETTING_XML_ELM_DEFAULT, value))
719     m_value = m_default = value;
720   else if (!update)
721   {
722     CLog::Log(LOGERROR, "CSettingInt: error reading the default value of \"%s\"", m_id.c_str());
723     return false;
724   }
725
726   const TiXmlNode *constraints = node->FirstChild(SETTING_XML_ELM_CONSTRAINTS);
727   if (constraints != NULL)
728   {
729     // get the entries
730     const TiXmlNode *options = constraints->FirstChild(SETTING_XML_ELM_OPTIONS);
731     if (options != NULL && options->FirstChild() != NULL)
732     {
733       if (options->FirstChild()->Type() == TiXmlNode::TINYXML_TEXT)
734         m_optionsFiller = options->FirstChild()->ValueStr();
735       else
736       {
737         m_options.clear();
738         const TiXmlElement *optionElement = options->FirstChildElement(SETTING_XML_ELM_OPTION);
739         while (optionElement != NULL)
740         {
741           std::pair<int, int> entry;
742           if (optionElement->QueryIntAttribute(SETTING_XML_ATTR_LABEL, &entry.first) == TIXML_SUCCESS && entry.first > 0)
743           {
744             entry.second = strtol(optionElement->FirstChild()->Value(), NULL, 10);
745             m_options.push_back(entry);
746           }
747
748           optionElement = optionElement->NextSiblingElement(SETTING_XML_ELM_OPTION);
749         }
750       }
751     }
752
753     // get minimum
754     XMLUtils::GetInt(constraints, SETTING_XML_ELM_MINIMUM, m_min);
755     // get step
756     XMLUtils::GetInt(constraints, SETTING_XML_ELM_STEP, m_step);
757     // get maximum
758     XMLUtils::GetInt(constraints, SETTING_XML_ELM_MAXIMUM, m_max);
759   }
760
761   return true;
762 }
763
764 bool CSettingInt::FromString(const std::string &value)
765 {
766   int iValue;
767   if (!fromString(value, iValue))
768     return false;
769
770   return SetValue(iValue);
771 }
772
773 std::string CSettingInt::ToString() const
774 {
775   std::ostringstream oss;
776   oss << m_value;
777
778   return oss.str();
779 }
780
781 bool CSettingInt::Equals(const std::string &value) const
782 {
783   int iValue;
784   return (fromString(value, iValue) && m_value == iValue);
785 }
786
787 bool CSettingInt::CheckValidity(const std::string &value) const
788 {
789   int iValue;
790   if (!fromString(value, iValue))
791     return false;
792
793   return CheckValidity(iValue);
794 }
795
796 bool CSettingInt::CheckValidity(int value) const
797 {
798   if (!m_options.empty())
799   {
800     //if the setting is an std::map, check if we got a valid value before assigning it
801     bool ok = false;
802     for (StaticIntegerSettingOptions::const_iterator it = m_options.begin(); it != m_options.end(); ++it)
803     {
804       if (it->second == value)
805       {
806         ok = true;
807         break;
808       }
809     }
810
811     if (!ok)
812       return false;
813   }
814   else if (m_optionsFiller.empty() && m_min != m_max &&
815           (value < m_min || value > m_max))
816     return false;
817
818   return true;
819 }
820
821 bool CSettingInt::SetValue(int value)
822 {
823   CExclusiveLock lock(m_critical);
824
825   if (value == m_value)
826     return true;
827
828   if (!CheckValidity(value))
829     return false;
830
831   int oldValue = m_value;
832   m_value = value;
833
834   if (!OnSettingChanging(this))
835   {
836     m_value = oldValue;
837
838     // the setting couldn't be changed because one of the
839     // callback handlers failed the OnSettingChanging()
840     // callback so we need to let all the callback handlers
841     // know that the setting hasn't changed
842     OnSettingChanging(this);
843     return false;
844   }
845
846   m_changed = m_value != m_default;
847   OnSettingChanged(this);
848   return true;
849 }
850
851 void CSettingInt::SetDefault(int value)
852 {
853   CExclusiveLock lock(m_critical);
854
855   m_default = value;
856   if (!m_changed)
857     m_value = m_default;
858 }
859
860 SettingOptionsType CSettingInt::GetOptionsType() const
861 {
862   CSharedLock lock(m_critical);
863   if (!m_options.empty())
864     return SettingOptionsTypeStatic;
865   if (!m_optionsFiller.empty())
866     return SettingOptionsTypeDynamic;
867
868   return SettingOptionsTypeNone;
869 }
870
871 DynamicIntegerSettingOptions CSettingInt::UpdateDynamicOptions()
872 {
873   CExclusiveLock lock(m_critical);
874   DynamicIntegerSettingOptions options;
875   if (m_optionsFiller.empty() || m_settingsManager == NULL)
876     return options;
877
878   IntegerSettingOptionsFiller filler = (IntegerSettingOptionsFiller)m_settingsManager->GetSettingOptionsFiller(this);
879   if (filler == NULL)
880     return options;
881
882   int bestMatchingValue = m_value;
883   filler(this, options, bestMatchingValue);
884
885   if (bestMatchingValue != m_value)
886     SetValue(bestMatchingValue);
887
888   bool changed = m_dynamicOptions.size() != options.size();
889   if (!changed)
890   {
891     for (size_t index = 0; index < options.size(); index++)
892     {
893       if (options[index].first.compare(m_dynamicOptions[index].first) != 0 ||
894           options[index].second != m_dynamicOptions[index].second)
895       {
896         changed = true;
897         break;
898       }
899     }
900   }
901
902   if (changed)
903   {
904     m_dynamicOptions = options;
905     OnSettingPropertyChanged(this, "options");
906   }
907
908   return options;
909 }
910
911 void CSettingInt::copy(const CSettingInt &setting)
912 {
913   CSetting::Copy(setting);
914
915   CExclusiveLock lock(m_critical);
916
917   m_value = setting.m_value;
918   m_default = setting.m_default;
919   m_min = setting.m_min;
920   m_step = setting.m_step;
921   m_max = setting.m_max;
922   m_options = setting.m_options;
923   m_optionsFiller = setting.m_optionsFiller;
924 }
925
926 bool CSettingInt::fromString(const std::string &strValue, int &value)
927 {
928   if (strValue.empty())
929     return false;
930
931   char *end = NULL;
932   value = (int)strtol(strValue.c_str(), &end, 10);
933   if (end != NULL && *end != '\0')
934     return false; 
935
936   return true;
937 }
938
939 CSettingNumber::CSettingNumber(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
940   : CSetting(id, settingsManager),
941     m_value(0.0), m_default(0.0),
942     m_min(0.0), m_step(1.0), m_max(0.0)
943 { }
944   
945 CSettingNumber::CSettingNumber(const std::string &id, const CSettingNumber &setting)
946   : CSetting(id, setting)
947 {
948   copy(setting);
949 }
950
951 CSettingNumber::CSettingNumber(const std::string &id, int label, float value, float minimum, float step, float maximum, CSettingsManager *settingsManager /* = NULL */)
952   : CSetting(id, settingsManager),
953     m_value(value), m_default(value),
954     m_min(minimum), m_step(step), m_max(maximum)
955 {
956   m_label = label;
957 }
958
959 CSetting* CSettingNumber::Clone(const std::string &id) const
960 {
961   return new CSettingNumber(id, *this);
962 }
963
964 bool CSettingNumber::Deserialize(const TiXmlNode *node, bool update /* = false */)
965 {
966   CExclusiveLock lock(m_critical);
967
968   if (!CSetting::Deserialize(node, update))
969     return false;
970     
971   // get the default value
972   double value;
973   if (XMLUtils::GetDouble(node, SETTING_XML_ELM_DEFAULT, value))
974     m_value = m_default = value;
975   else if (!update)
976   {
977     CLog::Log(LOGERROR, "CSettingNumber: error reading the default value of \"%s\"", m_id.c_str());
978     return false;
979   }
980     
981   const TiXmlNode *constraints = node->FirstChild(SETTING_XML_ELM_CONSTRAINTS);
982   if (constraints != NULL)
983   {
984     // get the minimum value
985     XMLUtils::GetDouble(constraints, SETTING_XML_ELM_MINIMUM, m_min);
986     // get the step value
987     XMLUtils::GetDouble(constraints, SETTING_XML_ELM_STEP, m_step);
988     // get the maximum value
989     XMLUtils::GetDouble(constraints, SETTING_XML_ELM_MAXIMUM, m_max);
990   }
991
992   return true;
993 }
994
995 bool CSettingNumber::FromString(const std::string &value)
996 {
997   double dValue;
998   if (!fromString(value, dValue))
999     return false;
1000
1001   return SetValue(dValue);
1002 }
1003
1004 std::string CSettingNumber::ToString() const
1005 {
1006   std::ostringstream oss;
1007   oss << m_value;
1008
1009   return oss.str();
1010 }
1011
1012 bool CSettingNumber::Equals(const std::string &value) const
1013 {
1014   double dValue;
1015   CSharedLock lock(m_critical);
1016   return (fromString(value, dValue) && m_value == dValue);
1017 }
1018
1019 bool CSettingNumber::CheckValidity(const std::string &value) const
1020 {
1021   double dValue;
1022   if (!fromString(value, dValue))
1023     return false;
1024
1025   return CheckValidity(dValue);
1026 }
1027
1028 bool CSettingNumber::CheckValidity(double value) const
1029 {
1030   CSharedLock lock(m_critical);
1031   if (m_min != m_max &&
1032      (value < m_min || value > m_max))
1033     return false;
1034
1035   return true;
1036 }
1037
1038 bool CSettingNumber::SetValue(double value)
1039 {
1040   CExclusiveLock lock(m_critical);
1041
1042   if (value == m_value)
1043     return true;
1044
1045   if (!CheckValidity(value))
1046     return false;
1047
1048   double oldValue = m_value;
1049   m_value = value;
1050
1051   if (!OnSettingChanging(this))
1052   {
1053     m_value = oldValue;
1054
1055     // the setting couldn't be changed because one of the
1056     // callback handlers failed the OnSettingChanging()
1057     // callback so we need to let all the callback handlers
1058     // know that the setting hasn't changed
1059     OnSettingChanging(this);
1060     return false;
1061   }
1062
1063   m_changed = m_value != m_default;
1064   OnSettingChanged(this);
1065   return true;
1066 }
1067
1068 void CSettingNumber::SetDefault(double value)
1069 {
1070   CExclusiveLock lock(m_critical);
1071
1072   m_default = value;
1073   if (!m_changed)
1074     m_value = m_default;
1075 }
1076
1077 void CSettingNumber::copy(const CSettingNumber &setting)
1078 {
1079   CSetting::Copy(setting);
1080   CExclusiveLock lock(m_critical);
1081
1082   m_value = setting.m_value;
1083   m_default = setting.m_default;
1084   m_min = setting.m_min;
1085   m_step = setting.m_step;
1086   m_max = setting.m_max;
1087 }
1088
1089 bool CSettingNumber::fromString(const std::string &strValue, double &value)
1090 {
1091   if (strValue.empty())
1092     return false;
1093
1094   char *end = NULL;
1095   value = strtod(strValue.c_str(), &end);
1096   if (end != NULL && *end != '\0')
1097     return false;
1098
1099   return true;
1100 }
1101
1102 CSettingString::CSettingString(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
1103   : CSetting(id, settingsManager),
1104     m_allowEmpty(false)
1105 { }
1106   
1107 CSettingString::CSettingString(const std::string &id, const CSettingString &setting)
1108   : CSetting(id, setting)
1109 {
1110   copy(setting);
1111 }
1112
1113 CSettingString::CSettingString(const std::string &id, int label, const std::string &value, CSettingsManager *settingsManager /* = NULL */)
1114   : CSetting(id, settingsManager),
1115     m_value(value), m_default(value),
1116     m_allowEmpty(false)
1117 {
1118   m_label = label;
1119 }
1120
1121 CSetting* CSettingString::Clone(const std::string &id) const
1122 {
1123   return new CSettingString(id, *this);
1124 }
1125
1126 bool CSettingString::Deserialize(const TiXmlNode *node, bool update /* = false */)
1127 {
1128   CExclusiveLock lock(m_critical);
1129
1130   if (!CSetting::Deserialize(node, update))
1131     return false;
1132
1133   const TiXmlNode *constraints = node->FirstChild(SETTING_XML_ELM_CONSTRAINTS);
1134   if (constraints != NULL)
1135   {
1136     // get allowempty (needs to be parsed before parsing the default value)
1137     XMLUtils::GetBoolean(constraints, SETTING_XML_ELM_ALLOWEMPTY, m_allowEmpty);
1138
1139     // get the entries
1140     const TiXmlNode *options = constraints->FirstChild(SETTING_XML_ELM_OPTIONS);
1141     if (options != NULL && options->FirstChild() != NULL &&
1142         options->FirstChild()->Type() == TiXmlNode::TINYXML_TEXT)
1143       m_optionsFiller = options->FirstChild()->ValueStr();
1144   }
1145
1146   // get the default value
1147   CStdString value;
1148   if (XMLUtils::GetString(node, SETTING_XML_ELM_DEFAULT, value) &&
1149      (!value.empty() || m_allowEmpty))
1150     m_value = m_default = value;
1151   else if (!update && !m_allowEmpty)
1152   {
1153     CLog::Log(LOGERROR, "CSettingString: error reading the default value of \"%s\"", m_id.c_str());
1154     return false;
1155   }
1156
1157   return true;
1158 }
1159
1160 bool CSettingString::CheckValidity(const std::string &value) const
1161 {
1162   CSharedLock lock(m_critical);
1163   if (!m_allowEmpty && value.empty())
1164     return false;
1165
1166   return true;
1167 }
1168
1169 bool CSettingString::SetValue(const std::string &value)
1170 {
1171   CExclusiveLock lock(m_critical);
1172
1173   if (value == m_value)
1174     return true;
1175     
1176   if (!CheckValidity(value))
1177     return false;
1178
1179   std::string oldValue = m_value;
1180   m_value = value;
1181
1182   if (!OnSettingChanging(this))
1183   {
1184     m_value = oldValue;
1185
1186     // the setting couldn't be changed because one of the
1187     // callback handlers failed the OnSettingChanging()
1188     // callback so we need to let all the callback handlers
1189     // know that the setting hasn't changed
1190     OnSettingChanging(this);
1191     return false;
1192   }
1193
1194   m_changed = m_value != m_default;
1195   OnSettingChanged(this);
1196   return true;
1197 }
1198
1199 void CSettingString::SetDefault(const std::string &value)
1200 {
1201   CSharedLock lock(m_critical);
1202
1203   m_default = value;
1204   if (!m_changed)
1205     m_value = m_default;
1206 }
1207
1208 SettingOptionsType CSettingString::GetOptionsType() const
1209 {
1210   CSharedLock lock(m_critical);
1211   if (!m_optionsFiller.empty())
1212     return SettingOptionsTypeDynamic;
1213
1214   return SettingOptionsTypeNone;
1215 }
1216
1217 DynamicStringSettingOptions CSettingString::UpdateDynamicOptions()
1218 {
1219   CExclusiveLock lock(m_critical);
1220   DynamicStringSettingOptions options;
1221   if (m_optionsFiller.empty() || m_settingsManager == NULL)
1222     return options;
1223
1224   StringSettingOptionsFiller filler = (StringSettingOptionsFiller)m_settingsManager->GetSettingOptionsFiller(this);
1225   if (filler == NULL)
1226     return options;
1227
1228   std::string bestMatchingValue = m_value;
1229   filler(this, options, bestMatchingValue);
1230
1231   if (bestMatchingValue != m_value)
1232     SetValue(bestMatchingValue);
1233
1234   // check if the list of items has changed
1235   bool changed = m_dynamicOptions.size() != options.size();
1236   if (!changed)
1237   {
1238     for (size_t index = 0; index < options.size(); index++)
1239     {
1240       if (options[index].first.compare(m_dynamicOptions[index].first) != 0 ||
1241           options[index].second.compare(m_dynamicOptions[index].second) != 0)
1242       {
1243         changed = true;
1244         break;
1245       }
1246     }
1247   }
1248
1249   if (changed)
1250   {
1251     m_dynamicOptions = options;
1252     OnSettingPropertyChanged(this, "options");
1253   }
1254
1255   return options;
1256 }
1257
1258 void CSettingString::copy(const CSettingString &setting)
1259 {
1260   CSetting::Copy(setting);
1261
1262   CExclusiveLock lock(m_critical);
1263   m_value = setting.m_value;
1264   m_default = setting.m_default;
1265   m_allowEmpty = setting.m_allowEmpty;
1266 }
1267   
1268 CSettingAction::CSettingAction(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
1269   : CSetting(id, settingsManager)
1270 { }
1271   
1272 CSettingAction::CSettingAction(const std::string &id, const CSettingAction &setting)
1273   : CSetting(id, setting)
1274 { }
1275
1276 CSetting* CSettingAction::Clone(const std::string &id) const
1277 {
1278   return new CSettingAction(id, *this);
1279 }
1280
1281 bool CSettingAction::Deserialize(const TiXmlNode *node, bool update /* = false */)
1282 {
1283   CSharedLock lock(m_critical);
1284
1285   if (!CSetting::Deserialize(node, update))
1286     return false;
1287     
1288   return true;
1289 }