settings: move <allowempty> tag into <constraints> tag
[vuplus_xbmc] / xbmc / settings / Setting.cpp
1 /*
2  *      Copyright (C) 2013 Team XBMC
3  *      http://www.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 "threads/SingleLock.h"
25 #include "utils/log.h"
26 #include "utils/StringUtils.h"
27 #include "utils/XBMCTinyXML.h"
28 #include "utils/XMLUtils.h"
29
30 #define XML_ELM_LEVEL       "level"
31 #define XML_ELM_DEFAULT     "default"
32 #define XML_ELM_VALUE       "value"
33
34 #define XML_ELM_CONSTRAINTS "constraints"
35 #define XML_ELM_OPTIONS     "options"
36 #define XML_ELM_MINIMUM     "minimum"
37 #define XML_ELM_STEP        "step"
38 #define XML_ELM_MAXIMUM     "maximum"
39
40 CSetting::CSetting(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
41   : ISetting(id, settingsManager),
42     m_callback(NULL),
43     m_label(-1), m_help(-1),
44     m_level(SettingLevelStandard),
45     m_changed(false)
46 { }
47   
48 CSetting::CSetting(const std::string &id, const CSetting &setting)
49   : ISetting(id, setting.m_settingsManager),
50     m_callback(NULL),
51     m_label(-1), m_help(-1),
52     m_level(SettingLevelStandard),
53     m_changed(false)
54 {
55   m_id = id;
56   Copy(setting);
57 }
58
59 bool CSetting::Deserialize(const TiXmlNode *node, bool update /* = false */)
60 {
61   // handle <visible> conditions
62   if (!ISetting::Deserialize(node, update))
63     return false;
64
65   const TiXmlElement *element = node->ToElement();
66   if (element == NULL)
67     return false;
68
69   // get the attributes label and help
70   int tmp = -1;
71   if (element->QueryIntAttribute(XML_ATTR_LABEL, &m_label) == TIXML_SUCCESS && tmp > 0)
72     m_label = tmp;
73   if (element->QueryIntAttribute(XML_ATTR_HELP, &m_help) == TIXML_SUCCESS && tmp > 0)
74     m_help = tmp;
75
76   // get the <level>
77   int level = -1;
78   if (XMLUtils::GetInt(node, XML_ELM_LEVEL, level))
79     m_level = (SettingLevel)level;
80     
81   if (m_level < (int)SettingLevelBasic || m_level > (int)SettingLevelInternal)
82     m_level = SettingLevelStandard;
83
84   const TiXmlNode *dependencies = node->FirstChild("dependencies");
85   if (dependencies != NULL)
86   {
87     const TiXmlNode *dependencyNode = dependencies->FirstChild("dependency");
88     while (dependencyNode != NULL)
89     {
90       CSettingDependency dependency(m_settingsManager);
91       if (dependency.Deserialize(dependencyNode))
92         m_dependencies.push_back(dependency);
93       else
94         CLog::Log(LOGWARNING, "CSetting: error reading <dependency> tag of \"%s\"", m_id.c_str());
95
96       dependencyNode = dependencyNode->NextSibling("dependency");
97     }
98   }
99
100   const TiXmlElement *control = node->FirstChildElement("control");
101   if (control != NULL)
102   {
103     if (!m_control.Deserialize(control, update) ||
104         m_control.GetType() == SettingControlTypeNone)
105     {
106       CLog::Log(LOGERROR, "CSetting: error reading <control> tag of \"%s\"", m_id.c_str());
107       return false;
108     }
109   }
110
111   const TiXmlNode *updates = node->FirstChild("updates");
112   if (updates != NULL)
113   {
114     const TiXmlElement *updateElem = updates->FirstChildElement("update");
115     while (updateElem != NULL)
116     {
117       CSettingUpdate update;
118       if (update.Deserialize(updateElem))
119       {
120         if (!m_updates.insert(update).second)
121           CLog::Log(LOGWARNING, "CSetting: duplicate <update> definition for \"%s\"", m_id.c_str());
122       }
123       else
124         CLog::Log(LOGWARNING, "CSetting: error reading <update> tag of \"%s\"", m_id.c_str());
125
126       updateElem = updateElem->NextSiblingElement("update");
127     }
128   }
129
130   if ((m_control.GetType() == SettingControlTypeSpinner || m_control.GetType() == SettingControlTypeEdit) &&
131         m_control.GetFormat() == SettingControlFormatNone)
132   {
133     CLog::Log(LOGERROR, "CSetting: invalid <control> tag of \"%s\"", m_id.c_str());
134     return false;
135   }
136     
137   return true;
138 }
139   
140 bool CSetting::OnSettingChanging(const CSetting *setting)
141 {
142   if (m_callback == NULL)
143     return true;
144     
145   return m_callback->OnSettingChanging(setting);
146 }
147   
148 void CSetting::OnSettingChanged(const CSetting *setting)
149 {
150   if (m_callback == NULL)
151     return;
152
153   m_callback->OnSettingChanged(setting);
154 }
155
156 void CSetting::OnSettingAction(const CSetting *setting)
157 {
158   if (m_callback == NULL)
159     return;
160
161   m_callback->OnSettingAction(setting);
162 }
163
164 bool CSetting::OnSettingUpdate(CSetting* &setting, const char *oldSettingId, const TiXmlNode *oldSettingNode)
165 {
166   if (m_callback == NULL)
167     return false;
168
169   return m_callback->OnSettingUpdate(setting, oldSettingId, oldSettingNode);
170 }
171
172 void CSetting::Copy(const CSetting &setting)
173 {
174   SetVisible(setting.IsVisible());
175   m_callback = setting.m_callback;
176   m_label = setting.m_label;
177   m_help = setting.m_help;
178   m_level = setting.m_level;
179   m_control = setting.m_control;
180   m_dependencies = setting.m_dependencies;
181   m_updates = setting.m_updates;
182   m_changed = setting.m_changed;
183 }
184   
185 CSettingBool::CSettingBool(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
186   : CSetting(id, settingsManager),
187     m_value(false), m_default(false)
188 {
189   m_control.SetType(SettingControlTypeCheckmark);
190   m_control.SetFormat(SettingControlFormatBoolean);
191   m_control.SetAttributes(SettingControlAttributeNone);
192 }
193   
194 CSettingBool::CSettingBool(const std::string &id, const CSettingBool &setting)
195   : CSetting(id, setting)
196 {
197   copy(setting);
198 }
199
200 CSettingBool::CSettingBool(const std::string &id, int label, bool value, CSettingsManager *settingsManager /* = NULL */)
201   : CSetting(id, settingsManager),
202     m_value(value), m_default(value)
203 {
204   m_label = label;
205
206   m_control.SetType(SettingControlTypeCheckmark);
207   m_control.SetFormat(SettingControlFormatBoolean);
208   m_control.SetAttributes(SettingControlAttributeNone);
209 }
210
211 bool CSettingBool::Deserialize(const TiXmlNode *node, bool update /* = false */)
212 {
213   CSingleLock lock(m_critical);
214
215   if (!CSetting::Deserialize(node, update))
216     return false;
217
218   if (m_control.GetType() != SettingControlTypeCheckmark ||
219       m_control.GetFormat() != SettingControlFormatBoolean ||
220       m_control.GetAttributes() != SettingControlAttributeNone)
221   {
222     CLog::Log(LOGERROR, "CSettingBool: invalid <control> of \"%s\"", m_id.c_str());
223     return false;
224   }
225     
226   // get the default value
227   bool value;
228   if (XMLUtils::GetBoolean(node, XML_ELM_DEFAULT, value))
229     m_value = m_default = value;
230   else if (!update)
231   {
232     CLog::Log(LOGERROR, "CSettingBool: error reading the default value of \"%s\"", m_id.c_str());
233     return false;
234   }
235
236   return true;
237 }
238   
239 bool CSettingBool::FromString(const std::string &value)
240 {
241   bool bValue;
242   if (!fromString(value, bValue))
243     return false;
244
245   return SetValue(bValue);
246 }
247
248 std::string CSettingBool::ToString() const
249 {
250   return m_value ? "true" : "false";
251 }
252
253 bool CSettingBool::Equals(const std::string &value) const
254 {
255   bool bValue;
256   return (fromString(value, bValue) && m_value == bValue);
257 }
258
259 bool CSettingBool::CheckValidity(const std::string &value) const
260 {
261   bool bValue;
262   return fromString(value, bValue);
263 }
264
265 bool CSettingBool::SetValue(bool value)
266 {
267   CSingleLock lock(m_critical);
268
269   if (value == m_value)
270     return true;
271
272   bool oldValue = m_value;
273   m_value = value;
274
275   if (!OnSettingChanging(this))
276   {
277     m_value = oldValue;
278
279     // the setting couldn't be changed because one of the
280     // callback handlers failed the OnSettingChanging()
281     // callback so we need to let all the callback handlers
282     // know that the setting hasn't changed
283     OnSettingChanging(this);
284     return false;
285   }
286
287   m_changed = m_value != m_default;
288   OnSettingChanged(this);
289   return true;
290 }
291   
292 void CSettingBool::SetDefault(bool value)
293 {
294   CSingleLock lock(m_critical);
295
296   m_default = value;
297   if (!m_changed)
298     m_value = m_default;
299 }
300
301 void CSettingBool::copy(const CSettingBool &setting)
302 {
303   CSetting::Copy(setting);
304
305   m_value = setting.m_value;
306   m_default = setting.m_default;
307 }
308   
309 bool CSettingBool::fromString(const std::string &strValue, bool &value) const
310 {
311   CSingleLock lock(m_critical);
312
313   if (StringUtils::EqualsNoCase(strValue, "true"))
314   {
315     value = true;
316     return true;
317   }
318   if (StringUtils::EqualsNoCase(strValue, "false"))
319   {
320     value = false;
321     return true;
322   }
323
324   return false;
325 }
326
327 CSettingInt::CSettingInt(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
328   : CSetting(id, settingsManager),
329     m_value(0), m_default(0),
330     m_min(0), m_step(1), m_max(0),
331     m_format(-1), m_labelMin(-1), m_strFormat("%i")
332 { }
333   
334 CSettingInt::CSettingInt(const std::string &id, const CSettingInt &setting)
335   : CSetting(id, setting)
336 {
337   copy(setting);
338 }
339
340 CSettingInt::CSettingInt(const std::string &id, int label, int value, int minimum, int step, int maximum, int format, int minimumLabel, CSettingsManager *settingsManager /* = NULL */)
341   : CSetting(id, settingsManager),
342     m_value(value), m_default(value),
343     m_min(minimum), m_step(step), m_max(maximum),
344     m_format(format), m_labelMin(minimumLabel), m_strFormat("%i")
345 {
346   m_label = label;
347
348   m_control.SetType(SettingControlTypeSpinner);
349   if (format < 0)
350     m_control.SetFormat(SettingControlFormatInteger);
351   else
352     m_control.SetFormat(SettingControlFormatString);
353   m_control.SetAttributes(SettingControlAttributeNone);
354 }
355
356 CSettingInt::CSettingInt(const std::string &id, int label, int value, int minimum, int step, int maximum, const std::string &format, CSettingsManager *settingsManager /* = NULL */)
357   : CSetting(id, settingsManager),
358     m_value(value), m_default(value),
359     m_min(minimum), m_step(step), m_max(maximum),
360     m_format(-1), m_labelMin(-1), m_strFormat(format)
361 {
362   m_label = label;
363
364   m_control.SetType(SettingControlTypeSpinner);
365   if (format.empty())
366   {
367       m_strFormat = "%i";
368       m_control.SetFormat(SettingControlFormatInteger);
369   }
370   else
371     m_control.SetFormat(SettingControlFormatString);
372   m_control.SetAttributes(SettingControlAttributeNone);
373 }
374
375 CSettingInt::CSettingInt(const std::string &id, int label, int value, const SettingOptions &options, CSettingsManager *settingsManager /* = NULL */)
376   : CSetting(id, settingsManager),
377     m_value(value), m_default(value),
378     m_min(0), m_step(1), m_max(0),
379     m_format(-1), m_labelMin(-1), m_strFormat("%i"),
380     m_options(options)
381 {
382   m_label = label;
383
384   m_control.SetType(SettingControlTypeSpinner);
385   m_control.SetFormat(SettingControlFormatString);
386   m_control.SetAttributes(SettingControlAttributeNone);
387 }
388
389 bool CSettingInt::Deserialize(const TiXmlNode *node, bool update /* = false */)
390 {
391   CSingleLock lock(m_critical);
392
393   if (!CSetting::Deserialize(node, update))
394     return false;
395
396   if (m_control.GetType() == SettingControlTypeCheckmark)
397   {
398     CLog::Log(LOGERROR, "CSettingInt: invalid <control> of \"%s\"", m_id.c_str());
399     return false;
400   }
401
402   // get the default value
403   int value;
404   if (XMLUtils::GetInt(node, XML_ELM_DEFAULT, value))
405     m_value = m_default = value;
406   else if (!update)
407   {
408     CLog::Log(LOGERROR, "CSettingInt: error reading the default value of \"%s\"", m_id.c_str());
409     return false;
410   }
411
412   const TiXmlNode *constraints = node->FirstChild(XML_ELM_CONSTRAINTS);
413   if (constraints != NULL)
414   {
415     // get the entries
416     const TiXmlNode *options = constraints->FirstChild(XML_ELM_OPTIONS);
417     if (options != NULL && options->FirstChild() != NULL)
418     {
419       if (options->FirstChild()->Type() == TiXmlNode::TINYXML_TEXT)
420         m_optionsFiller = options->FirstChild()->ValueStr();
421       else
422       {
423         m_options.clear();
424         const TiXmlElement *optionElement = options->FirstChildElement("option");
425         while (optionElement != NULL)
426         {
427           std::pair<int, int> entry;
428           if (optionElement->QueryIntAttribute("label", &entry.first) == TIXML_SUCCESS && entry.first > 0)
429           {
430             entry.second = strtol(optionElement->FirstChild()->Value(), NULL, 10);
431             m_options.push_back(entry);
432           }
433
434           optionElement = optionElement->NextSiblingElement("option");
435         }
436       }
437     }
438
439     // get minimum
440     if (XMLUtils::GetInt(constraints, XML_ELM_MINIMUM, m_min) &&
441         m_control.GetFormat() == SettingControlFormatString)
442     {
443       const TiXmlElement *minimumElement = constraints->FirstChildElement(XML_ELM_MINIMUM);
444       if (minimumElement->QueryIntAttribute(XML_ATTR_LABEL, &m_labelMin) != TIXML_SUCCESS)
445         m_labelMin = -1;
446     }
447     // get step
448     XMLUtils::GetInt(constraints, XML_ELM_STEP, m_step);
449     // get maximum
450     XMLUtils::GetInt(constraints, XML_ELM_MAXIMUM, m_max);
451
452     if (m_control.GetFormat() == SettingControlFormatString)
453     {
454       XMLUtils::GetInt(constraints, "formatlabel", m_format);
455
456       if (m_labelMin < 0)
457       {
458         CStdString strFormat;
459         if (XMLUtils::GetString(constraints, "format", strFormat) && !strFormat.empty())
460           m_strFormat = strFormat;
461       }
462     }
463   }
464
465   return true;
466 }
467
468 bool CSettingInt::FromString(const std::string &value)
469 {
470   int iValue;
471   if (!fromString(value, iValue))
472     return false;
473
474   return SetValue(iValue);
475 }
476
477 std::string CSettingInt::ToString() const
478 {
479   std::ostringstream oss;
480   oss << m_value;
481
482   return oss.str();
483 }
484
485 bool CSettingInt::Equals(const std::string &value) const
486 {
487   int iValue;
488   return (fromString(value, iValue) && m_value == iValue);
489 }
490
491 bool CSettingInt::CheckValidity(const std::string &value) const
492 {
493   int iValue;
494   if (!fromString(value, iValue))
495     return false;
496
497   return CheckValidity(iValue);
498 }
499
500 bool CSettingInt::CheckValidity(int value) const
501 {
502   if (!m_options.empty())
503   {
504     //if the setting is an std::map, check if we got a valid value before assigning it
505     bool ok = false;
506     for (SettingOptions::const_iterator it = m_options.begin(); it != m_options.end(); it++)
507     {
508       if (it->second == value)
509       {
510         ok = true;
511         break;
512       }
513     }
514
515     if (!ok)
516       return false;
517   }
518   else if (m_optionsFiller.empty() && m_min != m_max &&
519           (value < m_min || value > m_max))
520     return false;
521
522   return true;
523 }
524
525 bool CSettingInt::SetValue(int value)
526 {
527   CSingleLock lock(m_critical);
528
529   if (value == m_value)
530     return true;
531
532   if (!CheckValidity(value))
533     return false;
534
535   int oldValue = m_value;
536   m_value = value;
537
538   if (!OnSettingChanging(this))
539   {
540     m_value = oldValue;
541
542     // the setting couldn't be changed because one of the
543     // callback handlers failed the OnSettingChanging()
544     // callback so we need to let all the callback handlers
545     // know that the setting hasn't changed
546     OnSettingChanging(this);
547     return false;
548   }
549
550   m_changed = m_value != m_default;
551   OnSettingChanged(this);
552   return true;
553 }
554
555 void CSettingInt::SetDefault(int value)
556 {
557   CSingleLock lock(m_critical);
558
559   m_default = value;
560   if (!m_changed)
561     m_value = m_default;
562 }
563
564 void CSettingInt::copy(const CSettingInt &setting)
565 {
566   CSetting::Copy(setting);
567
568   m_value = setting.m_value;
569   m_default = setting.m_default;
570   m_min = setting.m_min;
571   m_step = setting.m_step;
572   m_max = setting.m_max;
573   m_format = setting.m_format;
574   m_labelMin = setting.m_labelMin;
575   m_strFormat = setting.m_strFormat;
576   m_options = setting.m_options;
577   m_optionsFiller = setting.m_optionsFiller;
578 }
579
580 bool CSettingInt::fromString(const std::string &strValue, int &value) const
581 {
582   if (strValue.empty())
583     return false;
584
585   char *end = NULL;
586   value = (int)strtol(strValue.c_str(), &end, 10);
587   if (end != NULL && *end != '\0')
588     return false; 
589
590   return true;
591 }
592
593 CSettingNumber::CSettingNumber(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
594   : CSetting(id, settingsManager),
595     m_value(0.0), m_default(0.0),
596     m_min(0.0), m_step(1.0), m_max(0.0)
597 { }
598   
599 CSettingNumber::CSettingNumber(const std::string &id, const CSettingNumber &setting)
600   : CSetting(id, setting)
601 {
602   copy(setting);
603 }
604
605 CSettingNumber::CSettingNumber(const std::string &id, int label, float value, float minimum, float step, float maximum, CSettingsManager *settingsManager /* = NULL */)
606   : CSetting(id, settingsManager),
607     m_value(value), m_default(value),
608     m_min(minimum), m_step(step), m_max(maximum)
609 {
610   m_label = label;
611
612   m_control.SetType(SettingControlTypeSpinner);
613   m_control.SetFormat(SettingControlFormatNumber);
614   m_control.SetAttributes(SettingControlAttributeNone);
615 }
616
617 bool CSettingNumber::Deserialize(const TiXmlNode *node, bool update /* = false */)
618 {
619   CSingleLock lock(m_critical);
620
621   if (!CSetting::Deserialize(node, update))
622     return false;
623     
624   if (m_control.GetType() == SettingControlTypeCheckmark)
625   {
626     CLog::Log(LOGERROR, "CSettingInt: invalid <control> of \"%s\"", m_id.c_str());
627     return false;
628   }
629     
630   // get the default value
631   double value;
632   if (XMLUtils::GetDouble(node, XML_ELM_DEFAULT, value))
633     m_value = m_default = value;
634   else if (!update)
635   {
636     CLog::Log(LOGERROR, "CSettingNumber: error reading the default value of \"%s\"", m_id.c_str());
637     return false;
638   }
639     
640   const TiXmlNode *constraints = node->FirstChild(XML_ELM_CONSTRAINTS);
641   if (constraints != NULL)
642   {
643     // get the minimum value
644     XMLUtils::GetDouble(constraints, XML_ELM_MINIMUM, m_min);
645     // get the step value
646     XMLUtils::GetDouble(constraints, XML_ELM_STEP, m_step);
647     // get the maximum value
648     XMLUtils::GetDouble(constraints, XML_ELM_MAXIMUM, m_max);
649   }
650
651   return true;
652 }
653
654 bool CSettingNumber::FromString(const std::string &value)
655 {
656   double dValue;
657   if (!fromString(value, dValue))
658     return false;
659
660   return SetValue(dValue);
661 }
662
663 std::string CSettingNumber::ToString() const
664 {
665   std::ostringstream oss;
666   oss << m_value;
667
668   return oss.str();
669 }
670
671 bool CSettingNumber::Equals(const std::string &value) const
672 {
673   double dValue;
674   return (fromString(value, dValue) && m_value == dValue);
675 }
676
677 bool CSettingNumber::CheckValidity(const std::string &value) const
678 {
679   double dValue;
680   if (!fromString(value, dValue))
681     return false;
682
683   return CheckValidity(dValue);
684 }
685
686 bool CSettingNumber::CheckValidity(double value) const
687 {
688   if (m_min != m_max &&
689      (value < m_min || value > m_max))
690     return false;
691
692   return true;
693 }
694
695 bool CSettingNumber::SetValue(double value)
696 {
697   CSingleLock lock(m_critical);
698
699   if (value == m_value)
700     return true;
701
702   if (!CheckValidity(value))
703     return false;
704
705   double oldValue = m_value;
706   m_value = value;
707
708   if (!OnSettingChanging(this))
709   {
710     m_value = oldValue;
711
712     // the setting couldn't be changed because one of the
713     // callback handlers failed the OnSettingChanging()
714     // callback so we need to let all the callback handlers
715     // know that the setting hasn't changed
716     OnSettingChanging(this);
717     return false;
718   }
719
720   m_changed = m_value != m_default;
721   OnSettingChanged(this);
722   return true;
723 }
724
725 void CSettingNumber::SetDefault(double value)
726 {
727   CSingleLock lock(m_critical);
728
729   m_default = value;
730   if (!m_changed)
731     m_value = m_default;
732 }
733
734 void CSettingNumber::copy(const CSettingNumber &setting)
735 {
736   CSetting::Copy(setting);
737
738   m_value = setting.m_value;
739   m_default = setting.m_default;
740   m_min = setting.m_min;
741   m_step = setting.m_step;
742   m_max = setting.m_max;
743 }
744
745 bool CSettingNumber::fromString(const std::string &strValue, double &value) const
746 {
747   if (strValue.empty())
748     return false;
749
750   char *end = NULL;
751   value = (int)strtod(strValue.c_str(), &end);
752   if (end != NULL && *end != '\0')
753     return false;
754
755   return true;
756 }
757
758 CSettingString::CSettingString(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
759   : CSetting(id, settingsManager),
760     m_allowEmpty(false), m_heading(-1)
761 { }
762   
763 CSettingString::CSettingString(const std::string &id, const CSettingString &setting)
764   : CSetting(id, setting)
765 {
766   copy(setting);
767 }
768
769 CSettingString::CSettingString(const std::string &id, int label, const std::string &value, CSettingsManager *settingsManager /* = NULL */)
770   : CSetting(id, settingsManager),
771     m_value(value), m_default(value),
772     m_allowEmpty(false), m_heading(-1)
773 {
774   m_label = label;
775
776   m_control.SetType(SettingControlTypeEdit);
777   m_control.SetFormat(SettingControlFormatString);
778   m_control.SetAttributes(SettingControlAttributeNone);
779 }
780
781 bool CSettingString::Deserialize(const TiXmlNode *node, bool update /* = false */)
782 {
783   CSingleLock lock(m_critical);
784
785   if (!CSetting::Deserialize(node, update))
786     return false;
787
788   if (m_control.GetType() == SettingControlTypeCheckmark ||
789       (m_control.GetType() == SettingControlTypeSpinner && (m_control.GetFormat() == SettingControlFormatInteger || m_control.GetFormat() == SettingControlFormatNumber)) ||
790       (m_control.GetType() == SettingControlTypeEdit && m_control.GetFormat() == SettingControlFormatNumber))
791   {
792     CLog::Log(LOGERROR, "CSettingString: invalid <control> of \"%s\"", m_id.c_str());
793     return false;
794   }
795   // get heading
796   XMLUtils::GetInt(node, "heading", m_heading);
797
798   const TiXmlNode *constraints = node->FirstChild(XML_ELM_CONSTRAINTS);
799   if (constraints != NULL)
800   {
801     // get allowempty (needs to be parsed before parsing the default value)
802     XMLUtils::GetBoolean(constraints, "allowempty", m_allowEmpty);
803
804     // get the entries
805     const TiXmlNode *options = constraints->FirstChild(XML_ELM_OPTIONS);
806     if (options != NULL && options->FirstChild() != NULL &&
807         options->FirstChild()->Type() == TiXmlNode::TINYXML_TEXT)
808       m_optionsFiller = options->FirstChild()->ValueStr();
809   }
810
811   // get the default value
812   CStdString value;
813   if (XMLUtils::GetString(node, XML_ELM_DEFAULT, value))
814     m_value = m_default = value;
815   else if (!update && !m_allowEmpty)
816   {
817     CLog::Log(LOGERROR, "CSettingString: error reading the default value of \"%s\"", m_id.c_str());
818     return false;
819   }
820
821   return true;
822 }
823
824 bool CSettingString::CheckValidity(const std::string &value) const
825 {
826   if (!m_allowEmpty && value.empty())
827     return false;
828
829   return true;
830 }
831
832 bool CSettingString::SetValue(const std::string &value)
833 {
834   CSingleLock lock(m_critical);
835
836   if (value == m_value)
837     return true;
838     
839   if (!CheckValidity(value))
840     return false;
841
842   std::string oldValue = m_value;
843   m_value = value;
844
845   if (!OnSettingChanging(this))
846   {
847     m_value = oldValue;
848
849     // the setting couldn't be changed because one of the
850     // callback handlers failed the OnSettingChanging()
851     // callback so we need to let all the callback handlers
852     // know that the setting hasn't changed
853     OnSettingChanging(this);
854     return false;
855   }
856
857   m_changed = m_value != m_default;
858   OnSettingChanged(this);
859   return true;
860 }
861
862 void CSettingString::SetDefault(const std::string &value)
863 {
864   CSingleLock lock(m_critical);
865
866   m_default = value;
867   if (!m_changed)
868     m_value = m_default;
869 }
870
871 void CSettingString::copy(const CSettingString &setting)
872 {
873   CSetting::Copy(setting);
874
875   m_value = setting.m_value;
876   m_default = setting.m_default;
877   m_allowEmpty = setting.m_allowEmpty;
878   m_heading = setting.m_heading;
879 }
880   
881 CSettingAction::CSettingAction(const std::string &id, CSettingsManager *settingsManager /* = NULL */)
882   : CSetting(id, settingsManager)
883 {
884   m_control.SetType(SettingControlTypeButton);
885   m_control.SetFormat(SettingControlFormatAction);
886   m_control.SetAttributes(SettingControlAttributeNone);
887 }
888   
889 CSettingAction::CSettingAction(const std::string &id, const CSettingAction &setting)
890   : CSetting(id, setting)
891 {
892   m_control.SetType(SettingControlTypeButton);
893   m_control.SetFormat(SettingControlFormatAction);
894   m_control.SetAttributes(SettingControlAttributeNone);
895 }
896
897 bool CSettingAction::Deserialize(const TiXmlNode *node, bool update /* = false */)
898 {
899   CSingleLock lock(m_critical);
900
901   if (!CSetting::Deserialize(node, update))
902     return false;
903     
904   if (m_control.GetType() != SettingControlTypeButton ||
905       m_control.GetFormat() != SettingControlFormatAction ||
906       m_control.GetAttributes() != SettingControlAttributeNone)
907   {
908     CLog::Log(LOGERROR, "CSettingAction: invalid <control> of \"%s\"", m_id.c_str());
909     return false;
910   }
911     
912   return true;
913 }