fixed: Debug logging enabled in the UI would reset itself on reboot.
[xbmc:xbmc-antiquated.git] / xbmc / Settings.cpp
1 /*
2  *      Copyright (C) 2005-2008 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, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "system.h"
23 #include "Settings.h"
24 #include "AdvancedSettings.h"
25 #include "Application.h"
26 #include "KeyboardLayoutConfiguration.h"
27 #include "Util.h"
28 #include "URL.h"
29 #include "GUIWindowFileManager.h"
30 #include "GUIDialogButtonMenu.h"
31 #include "GUIFontManager.h"
32 #include "LangCodeExpander.h"
33 #include "ButtonTranslator.h"
34 #include "XMLUtils.h"
35 #include "utils/PasswordManager.h"
36 #include "GUIAudioManager.h"
37 #include "AudioContext.h"
38 #include "utils/GUIInfoManager.h"
39 #include "utils/Network.h"
40 #include "FileSystem/MultiPathDirectory.h"
41 #include "FileSystem/SpecialProtocol.h"
42 #include "GUIBaseContainer.h" // for VIEW_TYPE enum
43 #include "MediaManager.h"
44 #include "DNSNameCache.h"
45 #include "GUIWindowManager.h"
46 #include "GUIDialogYesNo.h"
47 #include "FileSystem/Directory.h"
48 #include "FileItem.h"
49 #include "LangInfo.h"
50 #include "LocalizeStrings.h"
51 #include "StringUtils.h"
52 #ifdef _WIN32
53 #include "win32/WIN32Util.h"
54 #endif
55 #if defined(_LINUX) && defined(HAS_FILESYSTEM_SMB)
56 #include "FileSystem/SMBDirectory.h"
57 #endif
58 #include "playercorefactory/PlayerCoreFactory.h"
59
60 using namespace std;
61 using namespace XFILE;
62 using namespace DIRECTORY;
63
64 class CSettings g_settings;
65 struct CSettings::stSettings& g_stSettings = g_settings.m_stSettings;
66
67 extern CStdString g_LoadErrorStr;
68
69 CSettings::CSettings(void)
70 {
71 }
72
73 void CSettings::Initialize()
74 {
75   RESOLUTION_INFO res;
76   vector<RESOLUTION_INFO>::iterator it = m_ResInfo.begin();
77
78   m_ResInfo.insert(it, RES_CUSTOM, res);
79
80   for (int i = RES_HDTV_1080i; i <= RES_PAL60_16x9; i++)
81   {
82     g_graphicsContext.ResetScreenParameters((RESOLUTION)i);
83     g_graphicsContext.ResetOverscan((RESOLUTION)i, m_ResInfo[i].Overscan);
84   }
85
86   m_stSettings.m_iMyVideoStack = STACK_NONE;
87
88   m_stSettings.m_bMyMusicSongInfoInVis = true;    // UNUSED - depreciated.
89   m_stSettings.m_bMyMusicSongThumbInVis = false;  // used for music info in vis screen
90
91   m_stSettings.m_bMyMusicPlaylistRepeat = false;
92   m_stSettings.m_bMyMusicPlaylistShuffle = false;
93
94   m_stSettings.m_bMyVideoPlaylistRepeat = false;
95   m_stSettings.m_bMyVideoPlaylistShuffle = false;
96   m_stSettings.m_bMyVideoNavFlatten = false;
97   m_stSettings.m_bStartVideoWindowed = false;
98
99   m_stSettings.m_nVolumeLevel = 0;
100   m_stSettings.m_dynamicRangeCompressionLevel = 0;
101   m_stSettings.m_iPreMuteVolumeLevel = 0;
102   m_stSettings.m_bMute = false;
103   m_stSettings.m_fZoomAmount = 1.0f;
104   m_stSettings.m_fPixelRatio = 1.0f;
105
106   m_stSettings.m_pictureExtensions = ".png|.jpg|.jpeg|.bmp|.gif|.ico|.tif|.tiff|.tga|.pcx|.cbz|.zip|.cbr|.rar|.m3u|.dng|.nef|.cr2|.crw|.orf|.arw|.erf|.3fr|.dcr|.x3f|.mef|.raf|.mrw|.pef|.sr2";
107   m_stSettings.m_musicExtensions = ".nsv|.m4a|.flac|.aac|.strm|.pls|.rm|.rma|.mpa|.wav|.wma|.ogg|.mp3|.mp2|.m3u|.mod|.amf|.669|.dmf|.dsm|.far|.gdm|.imf|.it|.m15|.med|.okt|.s3m|.stm|.sfx|.ult|.uni|.xm|.sid|.ac3|.dts|.cue|.aif|.aiff|.wpl|.ape|.mac|.mpc|.mp+|.mpp|.shn|.zip|.rar|.wv|.nsf|.spc|.gym|.adplug|.adx|.dsp|.adp|.ymf|.ast|.afc|.hps|.xsp|.xwav|.waa|.wvs|.wam|.gcm|.idsp|.mpdsp|.mss|.spt|.rsd|.mid|.kar|.sap|.cmc|.cmr|.dmc|.mpt|.mpd|.rmt|.tmc|.tm8|.tm2|.oga|.url|.pxml|.tta";
108   m_stSettings.m_videoExtensions = ".m4v|.3g2|.3gp|.nsv|.tp|.ts|.ty|.strm|.pls|.rm|.rmvb|.m3u|.ifo|.mov|.qt|.divx|.xvid|.bivx|.vob|.nrg|.img|.iso|.pva|.wmv|.asf|.asx|.ogm|.m2v|.avi|.bin|.dat|.mpg|.mpeg|.mp4|.mkv|.avc|.vp3|.svq3|.nuv|.viv|.dv|.fli|.flv|.rar|.001|.wpl|.zip|.vdr|.dvr-ms|.xsp|.mts|.m2t|.m2ts|.evo|.ogv|.sdp|.avs|.rec|.url|.pxml|.vc1|.h264|.rcv";
109   // internal music extensions
110   m_stSettings.m_musicExtensions += "|.sidstream|.oggstream|.nsfstream|.asapstream|.cdda";
111
112   #ifdef __APPLE__
113     CStdString logDir = getenv("HOME");
114     logDir += "/Library/Logs/";
115     m_stSettings.m_logFolder = logDir;
116   #else
117     m_stSettings.m_logFolder = "special://home/";              // log file location
118   #endif
119
120   m_iLastLoadedProfileIndex = 0;
121
122   // defaults for scanning
123   m_stSettings.m_bMyMusicIsScanning = false;
124
125   m_stSettings.iAdditionalSubtitleDirectoryChecked = 0;
126   m_stSettings.m_iMyMusicStartWindow = WINDOW_MUSIC_FILES;
127   m_stSettings.m_iVideoStartWindow = WINDOW_VIDEO_FILES;
128   m_stSettings.m_iMyVideoWatchMode = VIDEO_SHOW_ALL;
129   m_stSettings.m_iSystemTimeTotalUp = 0;
130   m_stSettings.m_HttpApiBroadcastLevel = 0;
131   m_stSettings.m_HttpApiBroadcastPort = 8278;
132
133   bUseLoginScreen = false;
134 }
135
136 CSettings::~CSettings(void)
137 {
138   m_ResInfo.clear();
139 }
140
141
142 void CSettings::Save() const
143 {
144   if (g_application.m_bStop)
145   {
146     //don't save settings when we're busy stopping the application
147     //a lot of screens try to save settings on deinit and deinit is called
148     //for every screen when the application is stopping.
149     return ;
150   }
151   if (!SaveSettings(GetSettingsFile()))
152   {
153     CLog::Log(LOGERROR, "Unable to save settings to %s", GetSettingsFile().c_str());
154   }
155 }
156
157 bool CSettings::Reset()
158 {
159   CLog::Log(LOGINFO, "Resetting settings");
160   CFile::Delete(GetSettingsFile());
161   Save();
162   return LoadSettings(GetSettingsFile());
163 }
164
165 bool CSettings::Load(bool& bXboxMediacenter, bool& bSettings)
166 {
167   // load settings file...
168   bXboxMediacenter = bSettings = false;
169
170   CSpecialProtocol::SetProfilePath(GetProfileUserDataFolder());
171   CLog::Log(LOGNOTICE, "loading %s", GetSettingsFile().c_str());
172   if (!LoadSettings(GetSettingsFile()))
173   {
174     CLog::Log(LOGERROR, "Unable to load %s, creating new %s with default values", GetSettingsFile().c_str(), GetSettingsFile().c_str());
175     Save();
176     if (!(bSettings = Reset()))
177       return false;
178   }
179
180   // clear sources, then load xml file...
181   m_fileSources.clear();
182   m_musicSources.clear();
183   m_pictureSources.clear();
184   m_programSources.clear();
185   m_videoSources.clear();
186   CStdString strXMLFile = GetSourcesFile();
187   CLog::Log(LOGNOTICE, "%s", strXMLFile.c_str());
188   TiXmlDocument xmlDoc;
189   TiXmlElement *pRootElement = NULL;
190   if ( xmlDoc.LoadFile( strXMLFile ) )
191   {
192     pRootElement = xmlDoc.RootElement();
193     CStdString strValue;
194     if (pRootElement)
195       strValue = pRootElement->Value();
196     if ( strValue != "sources")
197       CLog::Log(LOGERROR, "%s sources.xml file does not contain <sources>", __FUNCTION__);
198   }
199   else if (CFile::Exists(strXMLFile))
200     CLog::Log(LOGERROR, "%s Error loading %s: Line %d, %s", __FUNCTION__, strXMLFile.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
201
202   // look for external sources file
203   TiXmlNode *pInclude = pRootElement ? pRootElement->FirstChild("remote") : NULL;
204   if (pInclude)
205   {
206     CStdString strRemoteFile = pInclude->FirstChild()->Value();
207     if (!strRemoteFile.IsEmpty())
208     {
209       CLog::Log(LOGDEBUG, "Found <remote> tag");
210       CLog::Log(LOGDEBUG, "Attempting to retrieve remote file: %s", strRemoteFile.c_str());
211       // sometimes we have to wait for the network
212       if (!g_application.getNetwork().IsAvailable(true) && CFile::Exists(strRemoteFile))
213       {
214         if ( xmlDoc.LoadFile(strRemoteFile) )
215         {
216           pRootElement = xmlDoc.RootElement();
217           CStdString strValue;
218           if (pRootElement)
219             strValue = pRootElement->Value();
220           if ( strValue != "sources")
221             CLog::Log(LOGERROR, "%s remote_sources.xml file does not contain <sources>", __FUNCTION__);
222         }
223         else
224           CLog::Log(LOGERROR, "%s unable to load file: %s, Line %d, %s", __FUNCTION__, strRemoteFile.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
225       }
226       else
227         CLog::Log(LOGNOTICE, "Could not retrieve remote file, defaulting to local sources");
228     }
229   }
230
231   if (pRootElement)
232   { // parse sources...
233     GetSources(pRootElement, "programs", m_programSources, m_defaultProgramSource);
234     GetSources(pRootElement, "pictures", m_pictureSources, m_defaultPictureSource);
235     GetSources(pRootElement, "files", m_fileSources, m_defaultFileSource);
236     GetSources(pRootElement, "music", m_musicSources, m_defaultMusicSource);
237     GetSources(pRootElement, "video", m_videoSources, m_defaultVideoSource);
238   }
239
240   bXboxMediacenter = true;
241
242   LoadRSSFeeds();
243   LoadUserFolderLayout();
244
245   return true;
246 }
247
248 VECSOURCES *CSettings::GetSourcesFromType(const CStdString &type)
249 {
250   if (type == "programs" || type == "myprograms")
251     return &m_programSources;
252   else if (type == "files")
253   {
254     // this nasty block of code is needed as we have to
255     // call getlocaldrives after localize strings has been loaded
256     bool bAdded=false;
257     for (unsigned int i=0;i<m_fileSources.size();++i)
258     {
259       if (m_fileSources[i].m_ignore)
260       {
261         bAdded = true;
262         break;
263       }
264     }
265     if (!bAdded)
266     {
267       VECSOURCES shares;
268       g_mediaManager.GetLocalDrives(shares, true);  // true to include Q
269       m_fileSources.insert(m_fileSources.end(),shares.begin(),shares.end());
270
271       CMediaSource source;
272       source.strName = g_localizeStrings.Get(22013);
273       source.m_ignore = true;
274       source.strPath = "special://profile/";
275       source.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
276       m_fileSources.push_back(source);
277     }
278
279     return &m_fileSources;
280   }
281   else if (type == "music")
282     return &m_musicSources;
283   else if (type == "video")
284     return &m_videoSources;
285   else if (type == "pictures")
286     return &m_pictureSources;
287
288   return NULL;
289 }
290
291 CStdString CSettings::GetDefaultSourceFromType(const CStdString &type)
292 {
293   CStdString defaultShare;
294   if (type == "programs" || type == "myprograms")
295     defaultShare = m_defaultProgramSource;
296   else if (type == "files")
297     defaultShare = m_defaultFileSource;
298   else if (type == "music")
299     defaultShare = m_defaultMusicSource;
300   else if (type == "video")
301     defaultShare = m_defaultVideoSource;
302   else if (type == "pictures")
303     defaultShare = m_defaultPictureSource;
304   return defaultShare;
305 }
306
307 void CSettings::GetSources(const TiXmlElement* pRootElement, const CStdString& strTagName, VECSOURCES& items, CStdString& strDefault)
308 {
309   //CLog::Log(LOGDEBUG, "  Parsing <%s> tag", strTagName.c_str());
310   strDefault = "";
311
312   items.clear();
313   const TiXmlNode *pChild = pRootElement->FirstChild(strTagName.c_str());
314   if (pChild)
315   {
316     pChild = pChild->FirstChild();
317     while (pChild > 0)
318     {
319       CStdString strValue = pChild->Value();
320       if (strValue == "source" || strValue == "bookmark") // "bookmark" left in for backwards compatibility
321       {
322         CMediaSource share;
323         if (GetSource(strTagName, pChild, share))
324         {
325           items.push_back(share);
326         }
327         else
328         {
329           CLog::Log(LOGERROR, "    Missing or invalid <name> and/or <path> in source");
330         }
331       }
332
333       if (strValue == "default")
334       {
335         const TiXmlNode *pValueNode = pChild->FirstChild();
336         if (pValueNode)
337         {
338           const char* pszText = pChild->FirstChild()->Value();
339           if (strlen(pszText) > 0)
340             strDefault = pszText;
341           CLog::Log(LOGDEBUG, "    Setting <default> source to : %s", strDefault.c_str());
342         }
343       }
344       pChild = pChild->NextSibling();
345     }
346   }
347   else
348   {
349     CLog::Log(LOGDEBUG, "  <%s> tag is missing or sources.xml is malformed", strTagName.c_str());
350   }
351 }
352
353 bool CSettings::GetSource(const CStdString &category, const TiXmlNode *source, CMediaSource &share)
354 {
355   //CLog::Log(LOGDEBUG,"    ---- SOURCE START ----");
356   const TiXmlNode *pNodeName = source->FirstChild("name");
357   CStdString strName;
358   if (pNodeName && pNodeName->FirstChild())
359   {
360     strName = pNodeName->FirstChild()->Value();
361     //CLog::Log(LOGDEBUG,"    Found name: %s", strName.c_str());
362   }
363   // get multiple paths
364   vector<CStdString> vecPaths;
365   const TiXmlElement *pPathName = source->FirstChildElement("path");
366   while (pPathName)
367   {
368     if (pPathName->FirstChild())
369     {
370       int pathVersion = 0;
371       pPathName->Attribute("pathversion", &pathVersion);
372       CStdString strPath = pPathName->FirstChild()->Value();
373       strPath = CSpecialProtocol::ReplaceOldPath(strPath, pathVersion);
374       // make sure there are no virtualpaths or stack paths defined in xboxmediacenter.xml
375       //CLog::Log(LOGDEBUG,"    Found path: %s", strPath.c_str());
376       if (!CUtil::IsVirtualPath(strPath) && !CUtil::IsStack(strPath))
377       {
378         // translate special tags
379         if (!strPath.IsEmpty() && strPath.at(0) == '$')
380         {
381           CStdString strPathOld(strPath);
382           strPath = CUtil::TranslateSpecialSource(strPath);
383           if (!strPath.IsEmpty())
384           {
385             //CLog::Log(LOGDEBUG,"    -> Translated to path: %s", strPath.c_str());
386           }
387           else
388           {
389             //CLog::Log(LOGERROR,"    -> Skipping invalid token: %s", strPathOld.c_str());
390             pPathName = pPathName->NextSiblingElement("path");
391             continue;
392           }
393         }
394         CUtil::AddSlashAtEnd(strPath);
395         vecPaths.push_back(strPath);
396       }
397       else
398         CLog::Log(LOGERROR,"    Invalid path type (%s) in source", strPath.c_str());
399     }
400     pPathName = pPathName->NextSiblingElement("path");
401   }
402
403   const TiXmlNode *pLockMode = source->FirstChild("lockmode");
404   const TiXmlNode *pLockCode = source->FirstChild("lockcode");
405   const TiXmlNode *pBadPwdCount = source->FirstChild("badpwdcount");
406   const TiXmlNode *pThumbnailNode = source->FirstChild("thumbnail");
407
408   if (!strName.IsEmpty() && vecPaths.size() > 0)
409   {
410     vector<CStdString> verifiedPaths;
411     // disallowed for files, or theres only a single path in the vector
412     if ((category.Equals("files")) || (vecPaths.size() == 1))
413       verifiedPaths.push_back(vecPaths[0]);
414
415     // multiple paths?
416     else
417     {
418       // validate the paths
419       for (int j = 0; j < (int)vecPaths.size(); ++j)
420       {
421         CURL url(vecPaths[j]);
422         CStdString protocol = url.GetProtocol();
423         bool bIsInvalid = false;
424
425         // for my programs
426         if (category.Equals("programs") || category.Equals("myprograms"))
427         {
428           // only allow HD and plugins
429           if (url.IsLocal() || protocol.Equals("plugin"))
430             verifiedPaths.push_back(vecPaths[j]);
431           else
432             bIsInvalid = true;
433         }
434
435         // for others allow everything (if the user does something silly, we can't stop them)
436         else
437           verifiedPaths.push_back(vecPaths[j]);
438
439         // error message
440         if (bIsInvalid)
441           CLog::Log(LOGERROR,"    Invalid path type (%s) for multipath source", vecPaths[j].c_str());
442       }
443
444       // no valid paths? skip to next source
445       if (verifiedPaths.size() == 0)
446       {
447         CLog::Log(LOGERROR,"    Missing or invalid <name> and/or <path> in source");
448         return false;
449       }
450     }
451
452     share.FromNameAndPaths(category, strName, verifiedPaths);
453
454 /*    CLog::Log(LOGDEBUG,"      Adding source:");
455     CLog::Log(LOGDEBUG,"        Name: %s", share.strName.c_str());
456     if (CUtil::IsVirtualPath(share.strPath) || CUtil::IsMultiPath(share.strPath))
457     {
458       for (int i = 0; i < (int)share.vecPaths.size(); ++i)
459         CLog::Log(LOGDEBUG,"        Path (%02i): %s", i+1, share.vecPaths.at(i).c_str());
460     }
461     else
462       CLog::Log(LOGDEBUG,"        Path: %s", share.strPath.c_str());
463 */
464     share.m_iBadPwdCount = 0;
465     if (pLockMode)
466     {
467       share.m_iLockMode = LockType(atoi(pLockMode->FirstChild()->Value()));
468       share.m_iHasLock = 2;
469     }
470
471     if (pLockCode)
472     {
473       if (pLockCode->FirstChild())
474         share.m_strLockCode = pLockCode->FirstChild()->Value();
475     }
476
477     if (pBadPwdCount)
478     {
479       if (pBadPwdCount->FirstChild())
480         share.m_iBadPwdCount = atoi( pBadPwdCount->FirstChild()->Value() );
481     }
482
483     if (pThumbnailNode)
484     {
485       if (pThumbnailNode->FirstChild())
486         share.m_strThumbnailImage = pThumbnailNode->FirstChild()->Value();
487     }
488
489     return true;
490   }
491   return false;
492 }
493
494 bool CSettings::GetPath(const TiXmlElement* pRootElement, const char *tagName, CStdString &strValue)
495 {
496   CStdString strDefault = strValue;
497   if (XMLUtils::GetPath(pRootElement, tagName, strValue))
498   { // tag exists
499     // check for "-" for backward compatibility
500     if (!strValue.Equals("-"))
501       return true;
502   }
503   // tag doesn't exist - set default
504   strValue = strDefault;
505   return false;
506 }
507
508 bool CSettings::GetString(const TiXmlElement* pRootElement, const char *tagName, CStdString &strValue, const CStdString& strDefaultValue)
509 {
510   if (XMLUtils::GetString(pRootElement, tagName, strValue))
511   { // tag exists
512     // check for "-" for backward compatibility
513     if (!strValue.Equals("-"))
514       return true;
515   }
516   // tag doesn't exist - set default
517   strValue = strDefaultValue;
518   return false;
519 }
520
521 bool CSettings::GetString(const TiXmlElement* pRootElement, const char *tagName, char *szValue, const CStdString& strDefaultValue)
522 {
523   CStdString strValue;
524   bool ret = GetString(pRootElement, tagName, strValue, strDefaultValue);
525   if (szValue)
526     strcpy(szValue, strValue.c_str());
527   return ret;
528 }
529
530 bool CSettings::GetInteger(const TiXmlElement* pRootElement, const char *tagName, int& iValue, const int iDefault, const int iMin, const int iMax)
531 {
532   if (XMLUtils::GetInt(pRootElement, tagName, iValue, iMin, iMax))
533     return true;
534   // default
535   iValue = iDefault;
536   return false;
537 }
538
539 bool CSettings::GetFloat(const TiXmlElement* pRootElement, const char *tagName, float& fValue, const float fDefault, const float fMin, const float fMax)
540 {
541   if (XMLUtils::GetFloat(pRootElement, tagName, fValue, fMin, fMax))
542     return true;
543   // default
544   fValue = fDefault;
545   return false;
546 }
547
548 void CSettings::GetViewState(const TiXmlElement *pRootElement, const CStdString &strTagName, CViewState &viewState, SORT_METHOD defaultSort, int defaultView)
549 {
550   const TiXmlElement* pNode = pRootElement->FirstChildElement(strTagName);
551   if (!pNode)
552   {
553     viewState.m_sortMethod = defaultSort;
554     viewState.m_viewMode = defaultView;
555     return;
556   }
557   GetInteger(pNode, "viewmode", viewState.m_viewMode, defaultView, DEFAULT_VIEW_LIST, DEFAULT_VIEW_MAX);
558   
559   int sortMethod;
560   GetInteger(pNode, "sortmethod", sortMethod, defaultSort, SORT_METHOD_NONE, SORT_METHOD_MAX);
561   viewState.m_sortMethod = (SORT_METHOD)sortMethod;
562
563   int sortOrder;
564   GetInteger(pNode, "sortorder", sortOrder, SORT_ORDER_ASC, SORT_ORDER_NONE, SORT_ORDER_DESC);
565   viewState.m_sortOrder = (SORT_ORDER)sortOrder;
566 }
567
568 void CSettings::SetViewState(TiXmlNode *pRootNode, const CStdString &strTagName, const CViewState &viewState) const
569 {
570   TiXmlElement newElement(strTagName);
571   TiXmlNode *pNewNode = pRootNode->InsertEndChild(newElement);
572   if (pNewNode)
573   {
574     XMLUtils::SetInt(pNewNode, "viewmode", viewState.m_viewMode);
575     XMLUtils::SetInt(pNewNode, "sortmethod", (int)viewState.m_sortMethod);
576     XMLUtils::SetInt(pNewNode, "sortorder", (int)viewState.m_sortOrder);
577   }
578 }
579
580 bool CSettings::LoadCalibration(const TiXmlElement* pRoot, const CStdString& strSettingsFile)
581 {
582   const TiXmlElement *pElement = pRoot->FirstChildElement("resolutions");
583   if (!pElement)
584   {
585     g_LoadErrorStr.Format("%s Doesn't contain <resolutions>", strSettingsFile.c_str());
586     return false;
587   }
588   const TiXmlElement *pResolution = pElement->FirstChildElement("resolution");
589   while (pResolution)
590   {
591     // get the data for this resolution
592     CStdString mode;
593     XMLUtils::GetString(pResolution, "description", mode);
594     // find this resolution in our resolution vector
595     for (unsigned int res = 0; res < m_ResInfo.size(); res++)
596     {
597       if (res == RES_WINDOW)
598         continue;
599       
600       if (m_ResInfo[res].strMode == mode)
601       { // found, read in the rest of the information for this item
602         const TiXmlElement *pOverscan = pResolution->FirstChildElement("overscan");
603         if (pOverscan)
604         {
605           GetInteger(pOverscan, "left", m_ResInfo[res].Overscan.left, 0, -m_ResInfo[res].iWidth / 4, m_ResInfo[res].iWidth / 4);
606           GetInteger(pOverscan, "top", m_ResInfo[res].Overscan.top, 0, -m_ResInfo[res].iHeight / 4, m_ResInfo[res].iHeight / 4);
607           GetInteger(pOverscan, "right", m_ResInfo[res].Overscan.right, m_ResInfo[res].iWidth, m_ResInfo[res].iWidth / 2, m_ResInfo[res].iWidth*3 / 2);
608           GetInteger(pOverscan, "bottom", m_ResInfo[res].Overscan.bottom, m_ResInfo[res].iHeight, m_ResInfo[res].iHeight / 2, m_ResInfo[res].iHeight*3 / 2);
609         }
610
611         // get the appropriate "safe graphics area" = 10% for 4x3, 3.5% for 16x9
612         float fSafe;
613         if (res == RES_PAL_4x3 || res == RES_NTSC_4x3 || res == RES_PAL60_4x3 || res == RES_HDTV_480p_4x3)
614           fSafe = 0.1f;
615         else
616           fSafe = 0.035f;
617
618         GetInteger(pResolution, "subtitles", m_ResInfo[res].iSubtitles, (int)((1 - fSafe)*m_ResInfo[res].iHeight), m_ResInfo[res].iHeight / 2, m_ResInfo[res].iHeight*5 / 4);
619         GetFloat(pResolution, "pixelratio", m_ResInfo[res].fPixelRatio, 128.0f / 117.0f, 0.5f, 2.0f);
620     /*    CLog::Log(LOGDEBUG, "  calibration for %s %ix%i", m_ResInfo[res].strMode, m_ResInfo[res].iWidth, m_ResInfo[res].iHeight);
621         CLog::Log(LOGDEBUG, "    subtitle yposition:%i pixelratio:%03.3f offsets:(%i,%i)->(%i,%i)",
622                   m_ResInfo[res].iSubtitles, m_ResInfo[res].fPixelRatio,
623                   m_ResInfo[res].Overscan.left, m_ResInfo[res].Overscan.top,
624                   m_ResInfo[res].Overscan.right, m_ResInfo[res].Overscan.bottom);*/
625       }
626     }
627     // iterate around
628     pResolution = pResolution->NextSiblingElement("resolution");
629
630
631 /* Hmm, these stuff shouldn't be releaded, they should be used instead of our internal
632    id counter to select what resolution is affected by this settings
633 #ifdef HAS_XRANDR
634     const CStdString def("");
635     CStdString val;
636     GetString(pResolution, "xrandrid", val, def);
637     strncpy(m_ResInfo[iRes].strId, val.c_str(), sizeof(m_ResInfo[iRes].strId));
638     GetString(pResolution, "output", val, def);
639     strncpy(m_ResInfo[iRes].strOutput, val.c_str(), sizeof(m_ResInfo[iRes].strOutput));
640     GetFloat(pResolution, "refreshrate", m_ResInfo[iRes].fRefreshRate, 0, 0, 200);
641 #endif
642 */
643   }
644   return true;
645 }
646
647 bool CSettings::SaveCalibration(TiXmlNode* pRootNode) const
648 {
649   TiXmlElement xmlRootElement("resolutions");
650   TiXmlNode *pRoot = pRootNode->InsertEndChild(xmlRootElement);
651
652   // save WINDOW, DESKTOP and CUSTOM resolution
653   for (size_t i = RES_WINDOW ; i < m_ResInfo.size() ; i++)
654   {
655     // Write the resolution tag
656     TiXmlElement resElement("resolution");
657     TiXmlNode *pNode = pRoot->InsertEndChild(resElement);
658     // Now write each of the pieces of information we need...
659     XMLUtils::SetString(pNode, "description", m_ResInfo[i].strMode);
660     XMLUtils::SetInt(pNode, "subtitles", m_ResInfo[i].iSubtitles);
661     XMLUtils::SetFloat(pNode, "pixelratio", m_ResInfo[i].fPixelRatio);
662 #ifdef HAS_XRANDR
663     XMLUtils::SetFloat(pNode, "refreshrate", m_ResInfo[i].fRefreshRate);
664     XMLUtils::SetString(pNode, "output", m_ResInfo[i].strOutput);
665     XMLUtils::SetString(pNode, "xrandrid", m_ResInfo[i].strId);
666 #endif
667     // create the overscan child
668     TiXmlElement overscanElement("overscan");
669     TiXmlNode *pOverscanNode = pNode->InsertEndChild(overscanElement);
670     XMLUtils::SetInt(pOverscanNode, "left", m_ResInfo[i].Overscan.left);
671     XMLUtils::SetInt(pOverscanNode, "top", m_ResInfo[i].Overscan.top);
672     XMLUtils::SetInt(pOverscanNode, "right", m_ResInfo[i].Overscan.right);
673     XMLUtils::SetInt(pOverscanNode, "bottom", m_ResInfo[i].Overscan.bottom);
674   }
675   return true;
676 }
677
678 bool CSettings::LoadSettings(const CStdString& strSettingsFile)
679 {
680   // load the xml file
681   TiXmlDocument xmlDoc;
682
683   if (!xmlDoc.LoadFile(strSettingsFile))
684   {
685     g_LoadErrorStr.Format("%s, Line %d\n%s", strSettingsFile.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
686     return false;
687   }
688
689   TiXmlElement *pRootElement = xmlDoc.RootElement();
690   if (strcmpi(pRootElement->Value(), "settings") != 0)
691   {
692     g_LoadErrorStr.Format("%s\nDoesn't contain <settings>", strSettingsFile.c_str());
693     return false;
694   }
695
696   // mymusic settings
697   TiXmlElement *pElement = pRootElement->FirstChildElement("mymusic");
698   if (pElement)
699   {
700     TiXmlElement *pChild = pElement->FirstChildElement("playlist");
701     if (pChild)
702     {
703       XMLUtils::GetBoolean(pChild, "repeat", m_stSettings.m_bMyMusicPlaylistRepeat);
704       XMLUtils::GetBoolean(pChild, "shuffle", m_stSettings.m_bMyMusicPlaylistShuffle);
705     }
706     // if the user happened to reboot in the middle of the scan we save this state
707     pChild = pElement->FirstChildElement("scanning");
708     if (pChild)
709     {
710       XMLUtils::GetBoolean(pChild, "isscanning", m_stSettings.m_bMyMusicIsScanning);
711     }
712     GetInteger(pElement, "startwindow", m_stSettings.m_iMyMusicStartWindow, WINDOW_MUSIC_FILES, WINDOW_MUSIC_FILES, WINDOW_MUSIC_NAV); //501; view songs
713     XMLUtils::GetBoolean(pElement, "songinfoinvis", m_stSettings.m_bMyMusicSongInfoInVis);
714     XMLUtils::GetBoolean(pElement, "songthumbinvis", m_stSettings.m_bMyMusicSongThumbInVis);
715     GetPath(pElement, "defaultlibview", m_defaultMusicLibSource);
716   }
717   // myvideos settings
718   pElement = pRootElement->FirstChildElement("myvideos");
719   if (pElement)
720   {
721     GetInteger(pElement, "startwindow", m_stSettings.m_iVideoStartWindow, WINDOW_VIDEO_FILES, WINDOW_VIDEO_FILES, WINDOW_VIDEO_NAV);
722     GetInteger(pElement, "stackvideomode", m_stSettings.m_iMyVideoStack, STACK_NONE, STACK_NONE, STACK_SIMPLE);
723
724     GetPath(pElement, "defaultlibview", m_defaultVideoLibSource);
725     GetInteger(pElement, "watchmode", m_stSettings.m_iMyVideoWatchMode, VIDEO_SHOW_ALL, VIDEO_SHOW_ALL, VIDEO_SHOW_WATCHED);
726     XMLUtils::GetBoolean(pElement, "flatten", m_stSettings.m_bMyVideoNavFlatten);
727
728     TiXmlElement *pChild = pElement->FirstChildElement("playlist");
729     if (pChild)
730     { // playlist
731       XMLUtils::GetBoolean(pChild, "repeat", m_stSettings.m_bMyVideoPlaylistRepeat);
732       XMLUtils::GetBoolean(pChild, "shuffle", m_stSettings.m_bMyVideoPlaylistShuffle);
733     }
734   }
735
736   pElement = pRootElement->FirstChildElement("viewstates");
737   if (pElement)
738   {
739     GetViewState(pElement, "musicnavartists", m_stSettings.m_viewStateMusicNavArtists);
740     GetViewState(pElement, "musicnavalbums", m_stSettings.m_viewStateMusicNavAlbums);
741     GetViewState(pElement, "musicnavsongs", m_stSettings.m_viewStateMusicNavSongs);
742     GetViewState(pElement, "musicshoutcast", m_stSettings.m_viewStateMusicShoutcast);
743     GetViewState(pElement, "musiclastfm", m_stSettings.m_viewStateMusicLastFM);
744     GetViewState(pElement, "videonavactors", m_stSettings.m_viewStateVideoNavActors);
745     GetViewState(pElement, "videonavyears", m_stSettings.m_viewStateVideoNavYears);
746     GetViewState(pElement, "videonavgenres", m_stSettings.m_viewStateVideoNavGenres);
747     GetViewState(pElement, "videonavtitles", m_stSettings.m_viewStateVideoNavTitles);
748     GetViewState(pElement, "videonavepisodes", m_stSettings.m_viewStateVideoNavEpisodes, SORT_METHOD_EPISODE);
749     GetViewState(pElement, "videonavtvshows", m_stSettings.m_viewStateVideoNavTvShows);
750     GetViewState(pElement, "videonavseasons", m_stSettings.m_viewStateVideoNavSeasons);
751     GetViewState(pElement, "videonavmusicvideos", m_stSettings.m_viewStateVideoNavMusicVideos);
752
753     GetViewState(pElement, "programs", m_stSettings.m_viewStatePrograms, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
754     GetViewState(pElement, "pictures", m_stSettings.m_viewStatePictures, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
755     GetViewState(pElement, "videofiles", m_stSettings.m_viewStateVideoFiles, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
756     GetViewState(pElement, "musicfiles", m_stSettings.m_viewStateMusicFiles, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
757   }
758
759   // general settings
760   pElement = pRootElement->FirstChildElement("general");
761   if (pElement)
762   {
763     GetInteger(pElement, "systemtotaluptime", m_stSettings.m_iSystemTimeTotalUp, 0, 0, INT_MAX);
764     GetInteger(pElement, "httpapibroadcastlevel", m_stSettings.m_HttpApiBroadcastLevel, 0, 0,5);
765     GetInteger(pElement, "httpapibroadcastport", m_stSettings.m_HttpApiBroadcastPort, 8278, 1, 65535);
766   }
767
768   pElement = pRootElement->FirstChildElement("defaultvideosettings");
769   if (pElement)
770   {
771     int interlaceMethod;
772     GetInteger(pElement, "interlacemethod", interlaceMethod, VS_INTERLACEMETHOD_NONE, VS_INTERLACEMETHOD_NONE, VS_INTERLACEMETHOD_INVERSE_TELECINE);
773     m_stSettings.m_defaultVideoSettings.m_InterlaceMethod = (EINTERLACEMETHOD)interlaceMethod;
774     int scalingMethod;
775     GetInteger(pElement, "scalingmethod", scalingMethod, VS_SCALINGMETHOD_LINEAR, VS_SCALINGMETHOD_NEAREST, VS_SCALINGMETHOD_CUBIC);
776     m_stSettings.m_defaultVideoSettings.m_ScalingMethod = (ESCALINGMETHOD)scalingMethod;
777
778     GetInteger(pElement, "viewmode", m_stSettings.m_defaultVideoSettings.m_ViewMode, VIEW_MODE_NORMAL, VIEW_MODE_NORMAL, VIEW_MODE_CUSTOM);
779     GetFloat(pElement, "zoomamount", m_stSettings.m_defaultVideoSettings.m_CustomZoomAmount, 1.0f, 0.5f, 2.0f);
780     GetFloat(pElement, "pixelratio", m_stSettings.m_defaultVideoSettings.m_CustomPixelRatio, 1.0f, 0.5f, 2.0f);
781     GetFloat(pElement, "volumeamplification", m_stSettings.m_defaultVideoSettings.m_VolumeAmplification, VOLUME_DRC_MINIMUM * 0.01f, VOLUME_DRC_MINIMUM * 0.01f, VOLUME_DRC_MAXIMUM * 0.01f);
782     GetFloat(pElement, "noisereduction", m_stSettings.m_defaultVideoSettings.m_NoiseReduction, 0.0f, 0.0f, 1.0f);
783     GetFloat(pElement, "sharpness", m_stSettings.m_defaultVideoSettings.m_Sharpness, 0.0f, -1.0f, 1.0f);
784     XMLUtils::GetBoolean(pElement, "outputtoallspeakers", m_stSettings.m_defaultVideoSettings.m_OutputToAllSpeakers);
785     XMLUtils::GetBoolean(pElement, "showsubtitles", m_stSettings.m_defaultVideoSettings.m_SubtitleOn);
786     GetFloat(pElement, "brightness", m_stSettings.m_defaultVideoSettings.m_Brightness, 50, 0, 100);
787     GetFloat(pElement, "contrast", m_stSettings.m_defaultVideoSettings.m_Contrast, 50, 0, 100);
788     GetFloat(pElement, "gamma", m_stSettings.m_defaultVideoSettings.m_Gamma, 20, 0, 100);
789     GetFloat(pElement, "audiodelay", m_stSettings.m_defaultVideoSettings.m_AudioDelay, 0.0f, -10.0f, 10.0f);
790     GetFloat(pElement, "subtitledelay", m_stSettings.m_defaultVideoSettings.m_SubtitleDelay, 0.0f, -10.0f, 10.0f);
791
792     m_stSettings.m_defaultVideoSettings.m_SubtitleCached = false;
793   }
794   // audio settings
795   pElement = pRootElement->FirstChildElement("audio");
796   if (pElement)
797   {
798     GetInteger(pElement, "volumelevel", m_stSettings.m_nVolumeLevel, VOLUME_MAXIMUM, VOLUME_MINIMUM, VOLUME_MAXIMUM);
799     GetInteger(pElement, "dynamicrangecompression", m_stSettings.m_dynamicRangeCompressionLevel, VOLUME_DRC_MINIMUM, VOLUME_DRC_MINIMUM, VOLUME_DRC_MAXIMUM);
800     for (int i = 0; i < 4; i++)
801     {
802       CStdString setting;
803       setting.Format("karaoke%i", i);
804 #define XVOICE_MASK_PARAM_DISABLED (-1.0f)
805       GetFloat(pElement, setting + "energy", m_stSettings.m_karaokeVoiceMask[i].energy, XVOICE_MASK_PARAM_DISABLED, XVOICE_MASK_PARAM_DISABLED, 1.0f);
806       GetFloat(pElement, setting + "pitch", m_stSettings.m_karaokeVoiceMask[i].pitch, XVOICE_MASK_PARAM_DISABLED, XVOICE_MASK_PARAM_DISABLED, 1.0f);
807       GetFloat(pElement, setting + "whisper", m_stSettings.m_karaokeVoiceMask[i].whisper, XVOICE_MASK_PARAM_DISABLED, XVOICE_MASK_PARAM_DISABLED, 1.0f);
808       GetFloat(pElement, setting + "robotic", m_stSettings.m_karaokeVoiceMask[i].robotic, XVOICE_MASK_PARAM_DISABLED, XVOICE_MASK_PARAM_DISABLED, 1.0f);
809     }
810   }
811
812   LoadCalibration(pRootElement, strSettingsFile);
813   g_guiSettings.LoadXML(pRootElement);
814   LoadSkinSettings(pRootElement);
815
816   // Configure the PlayerCoreFactory
817   LoadPlayerCoreFactorySettings("special://xbmc/system/playercorefactory.xml", true);
818   LoadPlayerCoreFactorySettings(GetUserDataItem("playercorefactory.xml"), false);
819
820   // Advanced settings
821   g_advancedSettings.Load();
822
823   // Default players?
824   CLog::Log(LOGNOTICE, "Default DVD Player: %s", g_advancedSettings.m_videoDefaultDVDPlayer.c_str());
825   CLog::Log(LOGNOTICE, "Default Video Player: %s", g_advancedSettings.m_videoDefaultPlayer.c_str());
826   CLog::Log(LOGNOTICE, "Default Audio Player: %s", g_advancedSettings.m_audioDefaultPlayer.c_str());
827
828   // setup any logging...
829   if (g_guiSettings.GetBool("debug.showloginfo"))
830   {
831     g_advancedSettings.m_logLevel = std::max(g_advancedSettings.m_logLevelHint, LOG_LEVEL_DEBUG_FREEMEM);
832     CLog::Log(LOGNOTICE, "Enabled debug logging due to GUI setting (%d)", g_advancedSettings.m_logLevel);
833   }
834   return true;
835 }
836
837 bool CSettings::LoadPlayerCoreFactorySettings(const CStdString& fileStr, bool clear)
838 {
839   CLog::Log(LOGNOTICE, "Loading player core factory settings from %s.", fileStr.c_str());
840   if (!CFile::Exists(fileStr))
841   { // tell the user it doesn't exist
842     CLog::Log(LOGNOTICE, "%s does not exist. Skipping.", fileStr.c_str());
843     return false;
844   }
845
846   TiXmlDocument playerCoreFactoryXML;
847   if (!playerCoreFactoryXML.LoadFile(fileStr))
848   {
849     CLog::Log(LOGERROR, "Error loading %s, Line %d (%s)", fileStr.c_str(), playerCoreFactoryXML.ErrorRow(), playerCoreFactoryXML.ErrorDesc());
850     return false;
851   }
852
853   return CPlayerCoreFactory::LoadConfiguration(playerCoreFactoryXML.RootElement(), clear);
854 }
855
856 bool CSettings::SaveSettings(const CStdString& strSettingsFile, CGUISettings *localSettings /* = NULL */) const
857 {
858   TiXmlDocument xmlDoc;
859   TiXmlElement xmlRootElement("settings");
860   TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
861   if (!pRoot) return false;
862   // write our tags one by one - just a big list for now (can be flashed up later)
863
864   // mymusic settings
865   TiXmlElement musicNode("mymusic");
866   TiXmlNode *pNode = pRoot->InsertEndChild(musicNode);
867   if (!pNode) return false;
868   {
869     TiXmlElement childNode("playlist");
870     TiXmlNode *pChild = pNode->InsertEndChild(childNode);
871     if (!pChild) return false;
872     XMLUtils::SetBoolean(pChild, "repeat", m_stSettings.m_bMyMusicPlaylistRepeat);
873     XMLUtils::SetBoolean(pChild, "shuffle", m_stSettings.m_bMyMusicPlaylistShuffle);
874   }
875   {
876     TiXmlElement childNode("scanning");
877     TiXmlNode *pChild = pNode->InsertEndChild(childNode);
878     if (!pChild) return false;
879     XMLUtils::SetBoolean(pChild, "isscanning", m_stSettings.m_bMyMusicIsScanning);
880   }
881
882   XMLUtils::SetInt(pNode, "startwindow", m_stSettings.m_iMyMusicStartWindow);
883   XMLUtils::SetBoolean(pNode, "songinfoinvis", m_stSettings.m_bMyMusicSongInfoInVis);
884   XMLUtils::SetBoolean(pNode, "songthumbinvis", m_stSettings.m_bMyMusicSongThumbInVis);
885   XMLUtils::SetPath(pNode, "defaultlibview", m_defaultMusicLibSource);
886
887   // myvideos settings
888   TiXmlElement videosNode("myvideos");
889   pNode = pRoot->InsertEndChild(videosNode);
890   if (!pNode) return false;
891
892   XMLUtils::SetInt(pNode, "startwindow", m_stSettings.m_iVideoStartWindow);
893
894   XMLUtils::SetInt(pNode, "stackvideomode", m_stSettings.m_iMyVideoStack);
895
896   XMLUtils::SetPath(pNode, "defaultlibview", m_defaultVideoLibSource);
897
898   XMLUtils::SetInt(pNode, "watchmode", m_stSettings.m_iMyVideoWatchMode);
899   XMLUtils::SetBoolean(pNode, "flatten", m_stSettings.m_bMyVideoNavFlatten);
900
901   { // playlist window
902     TiXmlElement childNode("playlist");
903     TiXmlNode *pChild = pNode->InsertEndChild(childNode);
904     if (!pChild) return false;
905     XMLUtils::SetBoolean(pChild, "repeat", m_stSettings.m_bMyVideoPlaylistRepeat);
906     XMLUtils::SetBoolean(pChild, "shuffle", m_stSettings.m_bMyVideoPlaylistShuffle);
907   }
908
909   // view states
910   TiXmlElement viewStateNode("viewstates");
911   pNode = pRoot->InsertEndChild(viewStateNode);
912   if (pNode)
913   {
914     SetViewState(pNode, "musicnavartists", m_stSettings.m_viewStateMusicNavArtists);
915     SetViewState(pNode, "musicnavalbums", m_stSettings.m_viewStateMusicNavAlbums);
916     SetViewState(pNode, "musicnavsongs", m_stSettings.m_viewStateMusicNavSongs);
917     SetViewState(pNode, "musicshoutcast", m_stSettings.m_viewStateMusicShoutcast);
918     SetViewState(pNode, "musiclastfm", m_stSettings.m_viewStateMusicLastFM);
919     SetViewState(pNode, "videonavactors", m_stSettings.m_viewStateVideoNavActors);
920     SetViewState(pNode, "videonavyears", m_stSettings.m_viewStateVideoNavYears);
921     SetViewState(pNode, "videonavgenres", m_stSettings.m_viewStateVideoNavGenres);
922     SetViewState(pNode, "videonavtitles", m_stSettings.m_viewStateVideoNavTitles);
923     SetViewState(pNode, "videonavepisodes", m_stSettings.m_viewStateVideoNavEpisodes);
924     SetViewState(pNode, "videonavseasons", m_stSettings.m_viewStateVideoNavSeasons);
925     SetViewState(pNode, "videonavtvshows", m_stSettings.m_viewStateVideoNavTvShows);
926     SetViewState(pNode, "videonavmusicvideos", m_stSettings.m_viewStateVideoNavMusicVideos);
927
928     SetViewState(pNode, "programs", m_stSettings.m_viewStatePrograms);
929     SetViewState(pNode, "pictures", m_stSettings.m_viewStatePictures);
930     SetViewState(pNode, "videofiles", m_stSettings.m_viewStateVideoFiles);
931     SetViewState(pNode, "musicfiles", m_stSettings.m_viewStateMusicFiles);
932   }
933
934   // general settings
935   TiXmlElement generalNode("general");
936   pNode = pRoot->InsertEndChild(generalNode);
937   if (!pNode) return false;
938   XMLUtils::SetInt(pNode, "systemtotaluptime", m_stSettings.m_iSystemTimeTotalUp);
939   XMLUtils::SetInt(pNode, "httpapibroadcastport", m_stSettings.m_HttpApiBroadcastPort);
940   XMLUtils::SetInt(pNode, "httpapibroadcastlevel", m_stSettings.m_HttpApiBroadcastLevel);
941
942   // default video settings
943   TiXmlElement videoSettingsNode("defaultvideosettings");
944   pNode = pRoot->InsertEndChild(videoSettingsNode);
945   if (!pNode) return false;
946   XMLUtils::SetInt(pNode, "interlacemethod", m_stSettings.m_defaultVideoSettings.m_InterlaceMethod);
947   XMLUtils::SetInt(pNode, "scalingmethod", m_stSettings.m_defaultVideoSettings.m_ScalingMethod);
948   XMLUtils::SetFloat(pNode, "noisereduction", m_stSettings.m_defaultVideoSettings.m_NoiseReduction);
949   XMLUtils::SetFloat(pNode, "sharpness", m_stSettings.m_defaultVideoSettings.m_Sharpness);
950   XMLUtils::SetInt(pNode, "viewmode", m_stSettings.m_defaultVideoSettings.m_ViewMode);
951   XMLUtils::SetFloat(pNode, "zoomamount", m_stSettings.m_defaultVideoSettings.m_CustomZoomAmount);
952   XMLUtils::SetFloat(pNode, "pixelratio", m_stSettings.m_defaultVideoSettings.m_CustomPixelRatio);
953   XMLUtils::SetFloat(pNode, "volumeamplification", m_stSettings.m_defaultVideoSettings.m_VolumeAmplification);
954   XMLUtils::SetBoolean(pNode, "outputtoallspeakers", m_stSettings.m_defaultVideoSettings.m_OutputToAllSpeakers);
955   XMLUtils::SetBoolean(pNode, "showsubtitles", m_stSettings.m_defaultVideoSettings.m_SubtitleOn);
956   XMLUtils::SetFloat(pNode, "brightness", m_stSettings.m_defaultVideoSettings.m_Brightness);
957   XMLUtils::SetFloat(pNode, "contrast", m_stSettings.m_defaultVideoSettings.m_Contrast);
958   XMLUtils::SetFloat(pNode, "gamma", m_stSettings.m_defaultVideoSettings.m_Gamma);
959   XMLUtils::SetFloat(pNode, "audiodelay", m_stSettings.m_defaultVideoSettings.m_AudioDelay);
960   XMLUtils::SetFloat(pNode, "subtitledelay", m_stSettings.m_defaultVideoSettings.m_SubtitleDelay);
961
962
963   // audio settings
964   TiXmlElement volumeNode("audio");
965   pNode = pRoot->InsertEndChild(volumeNode);
966   if (!pNode) return false;
967   XMLUtils::SetInt(pNode, "volumelevel", m_stSettings.m_nVolumeLevel);
968   XMLUtils::SetInt(pNode, "dynamicrangecompression", m_stSettings.m_dynamicRangeCompressionLevel);
969   for (int i = 0; i < 4; i++)
970   {
971     CStdString setting;
972     setting.Format("karaoke%i", i);
973     XMLUtils::SetFloat(pNode, setting + "energy", m_stSettings.m_karaokeVoiceMask[i].energy);
974     XMLUtils::SetFloat(pNode, setting + "pitch", m_stSettings.m_karaokeVoiceMask[i].pitch);
975     XMLUtils::SetFloat(pNode, setting + "whisper", m_stSettings.m_karaokeVoiceMask[i].whisper);
976     XMLUtils::SetFloat(pNode, setting + "robotic", m_stSettings.m_karaokeVoiceMask[i].robotic);
977   }
978
979   SaveCalibration(pRoot);
980
981   if (localSettings) // local settings to save
982     localSettings->SaveXML(pRoot);
983   else // save the global settings
984     g_guiSettings.SaveXML(pRoot);
985
986   SaveSkinSettings(pRoot);
987
988   // For mastercode
989   SaveProfiles( PROFILES_FILE );
990
991   // save the file
992   return xmlDoc.SaveFile(strSettingsFile);
993 }
994
995 bool CSettings::LoadProfile(int index)
996 {
997   int iOldIndex = m_iLastLoadedProfileIndex;
998   m_iLastLoadedProfileIndex = index;
999   bool bSourcesXML=true;
1000   CStdString strOldSkin = g_guiSettings.GetString("lookandfeel.skin");
1001   CStdString strOldFont = g_guiSettings.GetString("lookandfeel.font");
1002   CStdString strOldTheme = g_guiSettings.GetString("lookandfeel.skintheme");
1003   CStdString strOldColors = g_guiSettings.GetString("lookandfeel.skincolors");
1004   if (Load(bSourcesXML,bSourcesXML))
1005   {
1006     CreateProfileFolders();
1007
1008     // initialize our charset converter
1009     g_charsetConverter.reset();
1010
1011     // Load the langinfo to have user charset <-> utf-8 conversion
1012     CStdString strLanguage = g_guiSettings.GetString("locale.language");
1013     strLanguage[0] = toupper(strLanguage[0]);
1014
1015     CStdString strLangInfoPath;
1016     strLangInfoPath.Format("special://xbmc/language/%s/langinfo.xml", strLanguage.c_str());
1017     CLog::Log(LOGINFO, "load language info file:%s", strLangInfoPath.c_str());
1018     g_langInfo.Load(strLangInfoPath);
1019
1020     CStdString strLanguagePath;
1021     strLanguagePath.Format("special://xbmc/language/%s/strings.xml", strLanguage.c_str());
1022
1023     CButtonTranslator::GetInstance().Load();
1024     g_localizeStrings.Load(strLanguagePath);
1025
1026     g_infoManager.ResetCache();
1027     g_infoManager.ResetLibraryBools();
1028
1029     // always reload the skin - we need it for the new language strings
1030     g_application.LoadSkin(g_guiSettings.GetString("lookandfeel.skin"));
1031
1032     if (m_iLastLoadedProfileIndex != 0)
1033     {
1034       TiXmlDocument doc;
1035       if (doc.LoadFile(CUtil::AddFileToFolder(GetUserDataFolder(),"guisettings.xml")))
1036         g_guiSettings.LoadMasterLock(doc.RootElement());
1037     }
1038     
1039     CPasswordManager::GetInstance().Clear();
1040
1041     // to set labels - shares are reloaded
1042 #if !defined(_WIN32) && defined(HAS_DVD_DRIVE)
1043     MEDIA_DETECT::CDetectDVDMedia::UpdateState();
1044 #endif
1045     // init windows
1046     CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_WINDOW_RESET);
1047     g_windowManager.SendMessage(msg);
1048
1049     CUtil::DeleteMusicDatabaseDirectoryCache();
1050     CUtil::DeleteVideoDatabaseDirectoryCache();
1051
1052     return true;
1053   }
1054
1055   m_iLastLoadedProfileIndex = iOldIndex;
1056
1057   return false;
1058 }
1059
1060 bool CSettings::DeleteProfile(int index)
1061 {
1062   if (index < 0 && index >= (int)m_vecProfiles.size())
1063     return false;
1064
1065   CGUIDialogYesNo* dlgYesNo = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
1066   if (dlgYesNo)
1067   {
1068     CStdString message;
1069     CStdString str = g_localizeStrings.Get(13201);
1070     message.Format(str.c_str(), m_vecProfiles.at(index).getName());
1071     dlgYesNo->SetHeading(13200);
1072     dlgYesNo->SetLine(0, message);
1073     dlgYesNo->SetLine(1, "");
1074     dlgYesNo->SetLine(2, "");
1075     dlgYesNo->DoModal();
1076
1077     if (dlgYesNo->IsConfirmed())
1078     {
1079       //delete profile
1080       CStdString strDirectory = m_vecProfiles[index].getDirectory();
1081       m_vecProfiles.erase(m_vecProfiles.begin()+index);
1082       if (index == m_iLastLoadedProfileIndex)
1083       {
1084         LoadProfile(0);
1085         Save();
1086       }
1087
1088       CFileItem item(CUtil::AddFileToFolder(GetUserDataFolder(), strDirectory));
1089       item.m_strPath = CUtil::AddFileToFolder(GetUserDataFolder(), strDirectory + "\\");
1090       item.m_bIsFolder = true;
1091       item.Select(true);
1092       CGUIWindowFileManager::DeleteItem(&item);
1093     }
1094     else
1095       return false;
1096   }
1097
1098   SaveProfiles( PROFILES_FILE );
1099
1100   return true;
1101 }
1102
1103 bool CSettings::SaveSettingsToProfile(int index)
1104 {
1105   /*CProfile& profile = m_vecProfiles.at(index);
1106   return SaveSettings(profile.getFileName(), false);*/
1107   return true;
1108 }
1109
1110
1111 bool CSettings::LoadProfiles(const CStdString& strSettingsFile)
1112 {
1113   TiXmlDocument profilesDoc;
1114   if (!CFile::Exists(strSettingsFile))
1115   { // set defaults, or assume no rss feeds??
1116     return false;
1117   }
1118   if (!profilesDoc.LoadFile(strSettingsFile))
1119   {
1120     CLog::Log(LOGERROR, "Error loading %s, Line %d\n%s", strSettingsFile.c_str(), profilesDoc.ErrorRow(), profilesDoc.ErrorDesc());
1121     return false;
1122   }
1123
1124   TiXmlElement *pRootElement = profilesDoc.RootElement();
1125   if (!pRootElement || strcmpi(pRootElement->Value(),"profiles") != 0)
1126   {
1127     CLog::Log(LOGERROR, "Error loading %s, no <profiles> node", strSettingsFile.c_str());
1128     return false;
1129   }
1130   GetInteger(pRootElement,"lastloaded",m_iLastLoadedProfileIndex,0,0,1000);
1131   if (m_iLastLoadedProfileIndex < 0)
1132     m_iLastLoadedProfileIndex = 0;
1133
1134   XMLUtils::GetBoolean(pRootElement,"useloginscreen",bUseLoginScreen);
1135
1136   TiXmlElement* pProfile = pRootElement->FirstChildElement("profile");
1137   CProfile profile;
1138
1139   while (pProfile)
1140   {
1141     profile.setName("Master user");
1142     if (CDirectory::Exists("special://home/userdata"))
1143       profile.setDirectory("special://home/userdata");
1144     else
1145       profile.setDirectory("special://xbmc/userdata");
1146
1147     CStdString strName;
1148     XMLUtils::GetString(pProfile,"name",strName);
1149     profile.setName(strName);
1150
1151     CStdString strDirectory;
1152     XMLUtils::GetPath(pProfile,"directory",strDirectory);
1153     profile.setDirectory(strDirectory);
1154
1155     CStdString strThumb;
1156     XMLUtils::GetPath(pProfile,"thumbnail",strThumb);
1157     profile.setThumb(strThumb);
1158
1159     bool bHas=true;
1160     XMLUtils::GetBoolean(pProfile, "hasdatabases", bHas);
1161     profile.setDatabases(bHas);
1162
1163     bHas = true;
1164     XMLUtils::GetBoolean(pProfile, "canwritedatabases", bHas);
1165     profile.setWriteDatabases(bHas);
1166
1167     bHas = true;
1168     XMLUtils::GetBoolean(pProfile, "hassources", bHas);
1169     profile.setSources(bHas);
1170
1171     bHas = true;
1172     XMLUtils::GetBoolean(pProfile, "canwritesources", bHas);
1173     profile.setWriteSources(bHas);
1174
1175     bHas = false;
1176     XMLUtils::GetBoolean(pProfile, "locksettings", bHas);
1177     profile.setSettingsLocked(bHas);
1178
1179     bHas = false;
1180     XMLUtils::GetBoolean(pProfile, "lockfiles", bHas);
1181     profile.setFilesLocked(bHas);
1182
1183     bHas = false;
1184     XMLUtils::GetBoolean(pProfile, "lockmusic", bHas);
1185     profile.setMusicLocked(bHas);
1186
1187     bHas = false;
1188     XMLUtils::GetBoolean(pProfile, "lockvideo", bHas);
1189     profile.setVideoLocked(bHas);
1190
1191     bHas = false;
1192     XMLUtils::GetBoolean(pProfile, "lockpictures", bHas);
1193     profile.setPicturesLocked(bHas);
1194
1195     bHas = false;
1196     XMLUtils::GetBoolean(pProfile, "lockprograms", bHas);
1197     profile.setProgramsLocked(bHas);
1198
1199     LockType iLockMode;
1200     int lockMode = (int)LOCK_MODE_EVERYONE;
1201     XMLUtils::GetInt(pProfile,"lockmode",lockMode);
1202     iLockMode = (LockType)lockMode;
1203
1204     if (iLockMode > LOCK_MODE_QWERTY || iLockMode < LOCK_MODE_EVERYONE)
1205       iLockMode = LOCK_MODE_EVERYONE;
1206     profile.setLockMode(iLockMode);
1207
1208     CStdString strLockCode;
1209     XMLUtils::GetString(pProfile,"lockcode",strLockCode);
1210     profile.setLockCode(strLockCode);
1211
1212     CStdString strDate;
1213     XMLUtils::GetString(pProfile,"lastdate",strDate);
1214     profile.setDate(strDate);
1215
1216     m_vecProfiles.push_back(profile);
1217     pProfile = pProfile->NextSiblingElement("profile");
1218   }
1219
1220   if (m_iLastLoadedProfileIndex >= (int)m_vecProfiles.size() || m_iLastLoadedProfileIndex < 0)
1221     m_iLastLoadedProfileIndex = 0;
1222
1223   return true;
1224 }
1225
1226 bool CSettings::SaveProfiles(const CStdString& strSettingsFile) const
1227 {
1228   TiXmlDocument xmlDoc;
1229   TiXmlElement xmlRootElement("profiles");
1230   TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
1231   if (!pRoot) return false;
1232   XMLUtils::SetInt(pRoot,"lastloaded",m_iLastLoadedProfileIndex);
1233   XMLUtils::SetBoolean(pRoot,"useloginscreen",bUseLoginScreen);
1234   for (unsigned int iProfile=0;iProfile<m_vecProfiles.size();++iProfile)
1235   {
1236     TiXmlElement profileNode("profile");
1237     TiXmlNode *pNode = pRoot->InsertEndChild(profileNode);
1238     XMLUtils::SetString(pNode,"name",m_vecProfiles[iProfile].getName());
1239     XMLUtils::SetPath(pNode,"directory",m_vecProfiles[iProfile].getDirectory());
1240     XMLUtils::SetPath(pNode,"thumbnail",m_vecProfiles[iProfile].getThumb());
1241     XMLUtils::SetString(pNode,"lastdate",m_vecProfiles[iProfile].getDate());
1242
1243     if (m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE)
1244     {
1245       XMLUtils::SetInt(pNode,"lockmode",m_vecProfiles[iProfile].getLockMode());
1246       XMLUtils::SetString(pNode,"lockcode",m_vecProfiles[iProfile].getLockCode());
1247       XMLUtils::SetBoolean(pNode,"lockmusic",m_vecProfiles[iProfile].musicLocked());
1248       XMLUtils::SetBoolean(pNode,"lockvideo",m_vecProfiles[iProfile].videoLocked());
1249       XMLUtils::SetBoolean(pNode,"lockpictures",m_vecProfiles[iProfile].picturesLocked());
1250       XMLUtils::SetBoolean(pNode,"lockprograms",m_vecProfiles[iProfile].programsLocked());
1251       XMLUtils::SetBoolean(pNode,"locksettings",m_vecProfiles[iProfile].settingsLocked());
1252       XMLUtils::SetBoolean(pNode,"lockfiles",m_vecProfiles[iProfile].filesLocked());
1253     }
1254
1255     if (iProfile > 0)
1256     {
1257       XMLUtils::SetBoolean(pNode,"hasdatabases",m_vecProfiles[iProfile].hasDatabases());
1258       XMLUtils::SetBoolean(pNode,"canwritedatabases",m_vecProfiles[iProfile].canWriteDatabases());
1259       XMLUtils::SetBoolean(pNode,"hassources",m_vecProfiles[iProfile].hasSources());
1260       XMLUtils::SetBoolean(pNode,"canwritesources",m_vecProfiles[iProfile].canWriteSources());
1261     }
1262   }
1263   // save the file
1264   return xmlDoc.SaveFile(strSettingsFile);
1265 }
1266
1267 bool CSettings::LoadUPnPXml(const CStdString& strSettingsFile)
1268 {
1269   TiXmlDocument UPnPDoc;
1270
1271   if (!CFile::Exists(strSettingsFile))
1272   { // set defaults, or assume no rss feeds??
1273     return false;
1274   }
1275   if (!UPnPDoc.LoadFile(strSettingsFile))
1276   {
1277     CLog::Log(LOGERROR, "Error loading %s, Line %d\n%s", strSettingsFile.c_str(), UPnPDoc.ErrorRow(), UPnPDoc.ErrorDesc());
1278     return false;
1279   }
1280
1281   TiXmlElement *pRootElement = UPnPDoc.RootElement();
1282   if (!pRootElement || strcmpi(pRootElement->Value(),"upnpserver") != 0)
1283   {
1284     CLog::Log(LOGERROR, "Error loading %s, no <upnpserver> node", strSettingsFile.c_str());
1285     return false;
1286   }
1287   // load settings
1288
1289   // default values for ports
1290   m_UPnPPortServer = 0;
1291   m_UPnPPortRenderer = 0;
1292   m_UPnPMaxReturnedItems = 0;
1293
1294   XMLUtils::GetString(pRootElement, "UUID", m_UPnPUUIDServer);
1295   XMLUtils::GetInt(pRootElement, "Port", m_UPnPPortServer);
1296   XMLUtils::GetInt(pRootElement, "MaxReturnedItems", m_UPnPMaxReturnedItems);
1297   XMLUtils::GetString(pRootElement, "UUIDRenderer", m_UPnPUUIDRenderer);
1298   XMLUtils::GetInt(pRootElement, "PortRenderer", m_UPnPPortRenderer);
1299
1300   return true;
1301 }
1302
1303 bool CSettings::SaveUPnPXml(const CStdString& strSettingsFile) const
1304 {
1305   TiXmlDocument xmlDoc;
1306   TiXmlElement xmlRootElement("upnpserver");
1307   TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
1308   if (!pRoot) return false;
1309
1310   // create a new Element for UUID
1311   XMLUtils::SetString(pRoot, "UUID", m_UPnPUUIDServer);
1312   XMLUtils::SetInt(pRoot, "Port", m_UPnPPortServer);
1313   XMLUtils::SetInt(pRoot, "MaxReturnedItems", m_UPnPMaxReturnedItems);
1314   XMLUtils::SetString(pRoot, "UUIDRenderer", m_UPnPUUIDRenderer);
1315   XMLUtils::SetInt(pRoot, "PortRenderer", m_UPnPPortRenderer);
1316
1317   // save the file
1318   return xmlDoc.SaveFile(strSettingsFile);
1319 }
1320
1321 bool CSettings::UpdateShare(const CStdString &type, const CStdString oldName, const CMediaSource &share)
1322 {
1323   VECSOURCES *pShares = GetSourcesFromType(type);
1324
1325   if (!pShares) return false;
1326
1327   // update our current share list
1328   CMediaSource* pShare=NULL;
1329   for (IVECSOURCES it = pShares->begin(); it != pShares->end(); it++)
1330   {
1331     if ((*it).strName == oldName)
1332     {
1333       (*it).strName = share.strName;
1334       (*it).strPath = share.strPath;
1335       (*it).vecPaths = share.vecPaths;
1336       pShare = &(*it);
1337       break;
1338     }
1339   }
1340
1341   if (!pShare)
1342     return false;
1343
1344   // Update our XML file as well
1345   return SaveSources();
1346 }
1347
1348 // NOTE: This function does NOT save the sources.xml file - you need to call SaveSources() separately.
1349 bool CSettings::UpdateSource(const CStdString &strType, const CStdString strOldName, const CStdString &strUpdateElement, const CStdString &strUpdateText)
1350 {
1351   VECSOURCES *pShares = GetSourcesFromType(strType);
1352
1353   if (!pShares) return false;
1354
1355   // disallow virtual paths
1356   if (strUpdateElement.Equals("path") && CUtil::IsVirtualPath(strUpdateText))
1357     return false;
1358
1359   for (IVECSOURCES it = pShares->begin(); it != pShares->end(); it++)
1360   {
1361     if ((*it).strName == strOldName)
1362     {
1363       if ("name" == strUpdateElement)
1364         (*it).strName = strUpdateText;
1365       else if ("lockmode" == strUpdateElement)
1366         (*it).m_iLockMode = LockType(atoi(strUpdateText));
1367       else if ("lockcode" == strUpdateElement)
1368         (*it).m_strLockCode = strUpdateText;
1369       else if ("badpwdcount" == strUpdateElement)
1370         (*it).m_iBadPwdCount = atoi(strUpdateText);
1371       else if ("thumbnail" == strUpdateElement)
1372         (*it).m_strThumbnailImage = strUpdateText;
1373       else if ("path" == strUpdateElement)
1374       {
1375         (*it).vecPaths.clear();
1376         (*it).strPath = strUpdateText;
1377         (*it).vecPaths.push_back(strUpdateText);
1378       }
1379       else
1380         return false;
1381       return true;
1382     }
1383   }
1384   return false;
1385 }
1386
1387 bool CSettings::DeleteSource(const CStdString &strType, const CStdString strName, const CStdString strPath, bool virtualSource)
1388 {
1389   VECSOURCES *pShares = GetSourcesFromType(strType);
1390   if (!pShares) return false;
1391
1392   bool found(false);
1393
1394   for (IVECSOURCES it = pShares->begin(); it != pShares->end(); it++)
1395   {
1396     if ((*it).strName == strName && (*it).strPath == strPath)
1397     {
1398       CLog::Log(LOGDEBUG,"found share, removing!");
1399       pShares->erase(it);
1400       found = true;
1401       break;
1402     }
1403   }
1404
1405   if (virtualSource)
1406     return found;
1407
1408   return SaveSources();
1409 }
1410
1411 bool CSettings::AddShare(const CStdString &type, const CMediaSource &share)
1412 {
1413   VECSOURCES *pShares = GetSourcesFromType(type);
1414   if (!pShares) return false;
1415
1416   // translate dir and add to our current shares
1417   CStdString strPath1 = share.strPath;
1418   strPath1.ToUpper();
1419   if(strPath1.IsEmpty())
1420   {
1421     CLog::Log(LOGERROR, "unable to add empty path");
1422     return false;
1423   }
1424
1425   CMediaSource shareToAdd = share;
1426   if (strPath1.at(0) == '$')
1427   {
1428     shareToAdd.strPath = CUtil::TranslateSpecialSource(strPath1);
1429     if (!share.strPath.IsEmpty())
1430       CLog::Log(LOGDEBUG, "%s Translated (%s) to Path (%s)",__FUNCTION__ ,strPath1.c_str(),shareToAdd.strPath.c_str());
1431     else
1432     {
1433       CLog::Log(LOGDEBUG, "%s Skipping invalid special directory token: %s",__FUNCTION__,strPath1.c_str());
1434       return false;
1435     }
1436   }
1437   pShares->push_back(shareToAdd);
1438
1439   if (!share.m_ignore)
1440   {
1441     return SaveSources();
1442   }
1443   return true;
1444 }
1445
1446 bool CSettings::SaveSources()
1447 {
1448   // TODO: Should we be specifying utf8 here??
1449   TiXmlDocument doc;
1450   TiXmlElement xmlRootElement("sources");
1451   TiXmlNode *pRoot = doc.InsertEndChild(xmlRootElement);
1452   if (!pRoot) return false;
1453
1454   // ok, now run through and save each sources section
1455   SetSources(pRoot, "programs", m_programSources, m_defaultProgramSource);
1456   SetSources(pRoot, "video", m_videoSources, m_defaultVideoSource);
1457   SetSources(pRoot, "music", m_musicSources, m_defaultMusicSource);
1458   SetSources(pRoot, "pictures", m_pictureSources, m_defaultPictureSource);
1459   SetSources(pRoot, "files", m_fileSources, m_defaultFileSource);
1460
1461   return doc.SaveFile(GetSourcesFile());
1462 }
1463
1464 bool CSettings::SetSources(TiXmlNode *root, const char *section, const VECSOURCES &shares, const char *defaultPath)
1465 {
1466   TiXmlElement sectionElement(section);
1467   TiXmlNode *sectionNode = root->InsertEndChild(sectionElement);
1468   if (sectionNode)
1469   {
1470     XMLUtils::SetPath(sectionNode, "default", defaultPath);
1471     for (unsigned int i = 0; i < shares.size(); i++)
1472     {
1473       const CMediaSource &share = shares[i];
1474       if (share.m_ignore)
1475         continue;
1476       TiXmlElement source("source");
1477
1478       XMLUtils::SetString(&source, "name", share.strName);
1479
1480       for (unsigned int i = 0; i < share.vecPaths.size(); i++)
1481         XMLUtils::SetPath(&source, "path", share.vecPaths[i]);
1482
1483       if (share.m_iHasLock)
1484       {
1485         XMLUtils::SetInt(&source, "lockmode", share.m_iLockMode);
1486         XMLUtils::SetString(&source, "lockcode", share.m_strLockCode);
1487         XMLUtils::SetInt(&source, "badpwdcount", share.m_iBadPwdCount);
1488       }
1489       if (!share.m_strThumbnailImage.IsEmpty())
1490         XMLUtils::SetPath(&source, "thumbnail", share.m_strThumbnailImage);
1491
1492       sectionNode->InsertEndChild(source);
1493     }
1494   }
1495   return true;
1496 }
1497
1498 void CSettings::LoadSkinSettings(const TiXmlElement* pRootElement)
1499 {
1500   int number = 0;
1501   const TiXmlElement *pElement = pRootElement->FirstChildElement("skinsettings");
1502   if (pElement)
1503   {
1504     m_skinStrings.clear();
1505     m_skinBools.clear();
1506     const TiXmlElement *pChild = pElement->FirstChildElement("setting");
1507     while (pChild)
1508     {
1509       CStdString settingName = pChild->Attribute("name");
1510       if (pChild->Attribute("type") && strcmpi(pChild->Attribute("type"),"string") == 0)
1511       { // string setting
1512         CSkinString string;
1513         string.name = settingName;
1514         string.value = pChild->FirstChild() ? pChild->FirstChild()->Value() : "";
1515         m_skinStrings.insert(pair<int, CSkinString>(number++, string));
1516       }
1517       else
1518       { // bool setting
1519         CSkinBool setting;
1520         setting.name = settingName;
1521         setting.value = pChild->FirstChild() ? strcmpi(pChild->FirstChild()->Value(), "true") == 0 : false;
1522         m_skinBools.insert(pair<int, CSkinBool>(number++, setting));
1523       }
1524       pChild = pChild->NextSiblingElement("setting");
1525     }
1526   }
1527 }
1528
1529 void CSettings::SaveSkinSettings(TiXmlNode *pRootElement) const
1530 {
1531   // add the <skinsettings> tag
1532   TiXmlElement xmlSettingsElement("skinsettings");
1533   TiXmlNode *pSettingsNode = pRootElement->InsertEndChild(xmlSettingsElement);
1534   if (!pSettingsNode) return;
1535   for (map<int, CSkinBool>::const_iterator it = m_skinBools.begin(); it != m_skinBools.end(); ++it)
1536   {
1537     // Add a <setting type="bool" name="name">true/false</setting>
1538     TiXmlElement xmlSetting("setting");
1539     xmlSetting.SetAttribute("type", "bool");
1540     xmlSetting.SetAttribute("name", (*it).second.name.c_str());
1541     TiXmlText xmlBool((*it).second.value ? "true" : "false");
1542     xmlSetting.InsertEndChild(xmlBool);
1543     pSettingsNode->InsertEndChild(xmlSetting);
1544   }
1545   for (map<int, CSkinString>::const_iterator it = m_skinStrings.begin(); it != m_skinStrings.end(); ++it)
1546   {
1547     // Add a <setting type="string" name="name">string</setting>
1548     TiXmlElement xmlSetting("setting");
1549     xmlSetting.SetAttribute("type", "string");
1550     xmlSetting.SetAttribute("name", (*it).second.name.c_str());
1551     TiXmlText xmlLabel((*it).second.value);
1552     xmlSetting.InsertEndChild(xmlLabel);
1553     pSettingsNode->InsertEndChild(xmlSetting);
1554   }
1555 }
1556
1557 void CSettings::Clear()
1558 {
1559   m_programSources.clear();
1560   m_pictureSources.clear();
1561   m_fileSources.clear();
1562   m_musicSources.clear();
1563   m_videoSources.clear();
1564 //  m_vecIcons.clear();
1565   m_vecProfiles.clear();
1566   m_mapRssUrls.clear();
1567   m_skinBools.clear();
1568   m_skinStrings.clear();
1569 }
1570
1571 int CSettings::TranslateSkinString(const CStdString &setting)
1572 {
1573   CStdString settingName;
1574   settingName.Format("%s.%s", g_guiSettings.GetString("lookandfeel.skin").c_str(), setting);
1575   // run through and see if we have this setting
1576   for (map<int, CSkinString>::const_iterator it = m_skinStrings.begin(); it != m_skinStrings.end(); it++)
1577   {
1578     if (settingName.Equals((*it).second.name))
1579       return (*it).first;
1580   }
1581   // didn't find it - insert it
1582   CSkinString skinString;
1583   skinString.name = settingName;
1584   m_skinStrings.insert(pair<int, CSkinString>(m_skinStrings.size() + m_skinBools.size(), skinString));
1585   return m_skinStrings.size() + m_skinBools.size() - 1;
1586 }
1587
1588 const CStdString &CSettings::GetSkinString(int setting) const
1589 {
1590   map<int, CSkinString>::const_iterator it = m_skinStrings.find(setting);
1591   if (it != m_skinStrings.end())
1592   {
1593     return (*it).second.value;
1594   }
1595   return StringUtils::EmptyString;
1596 }
1597
1598 void CSettings::SetSkinString(int setting, const CStdString &label)
1599 {
1600   map<int, CSkinString>::iterator it = m_skinStrings.find(setting);
1601   if (it != m_skinStrings.end())
1602   {
1603     (*it).second.value = label;
1604     return;
1605   }
1606   assert(false);
1607   CLog::Log(LOGFATAL, "%s : Unknown setting requested", __FUNCTION__);
1608 }
1609
1610 void CSettings::ResetSkinSetting(const CStdString &setting)
1611 {
1612   CStdString settingName;
1613   settingName.Format("%s.%s", g_guiSettings.GetString("lookandfeel.skin").c_str(), setting);
1614   // run through and see if we have this setting as a string
1615   for (map<int, CSkinString>::iterator it = m_skinStrings.begin(); it != m_skinStrings.end(); it++)
1616   {
1617     if (settingName.Equals((*it).second.name))
1618     {
1619       (*it).second.value = "";
1620       return;
1621     }
1622   }
1623   // and now check for the skin bool
1624   for (map<int, CSkinBool>::iterator it = m_skinBools.begin(); it != m_skinBools.end(); it++)
1625   {
1626     if (settingName.Equals((*it).second.name))
1627     {
1628       (*it).second.value = false;
1629       return;
1630     }
1631   }
1632 }
1633
1634 int CSettings::TranslateSkinBool(const CStdString &setting)
1635 {
1636   CStdString settingName;
1637   settingName.Format("%s.%s", g_guiSettings.GetString("lookandfeel.skin").c_str(), setting);
1638   // run through and see if we have this setting
1639   for (map<int, CSkinBool>::const_iterator it = m_skinBools.begin(); it != m_skinBools.end(); it++)
1640   {
1641     if (settingName.Equals((*it).second.name))
1642       return (*it).first;
1643   }
1644   // didn't find it - insert it
1645   CSkinBool skinBool;
1646   skinBool.name = settingName;
1647   skinBool.value = false;
1648   m_skinBools.insert(pair<int, CSkinBool>(m_skinBools.size() + m_skinStrings.size(), skinBool));
1649   return m_skinBools.size() + m_skinStrings.size() - 1;
1650 }
1651
1652 bool CSettings::GetSkinBool(int setting) const
1653 {
1654   map<int, CSkinBool>::const_iterator it = m_skinBools.find(setting);
1655   if (it != m_skinBools.end())
1656   {
1657     return (*it).second.value;
1658   }
1659   // default is to return false
1660   return false;
1661 }
1662
1663 void CSettings::SetSkinBool(int setting, bool set)
1664 {
1665   map<int, CSkinBool>::iterator it = m_skinBools.find(setting);
1666   if (it != m_skinBools.end())
1667   {
1668     (*it).second.value = set;
1669     return;
1670   }
1671   assert(false);
1672   CLog::Log(LOGFATAL,"%s : Unknown setting requested", __FUNCTION__);
1673 }
1674
1675 void CSettings::ResetSkinSettings()
1676 {
1677   CStdString currentSkin = g_guiSettings.GetString("lookandfeel.skin") + ".";
1678   // clear all the settings and strings from this skin.
1679   map<int, CSkinBool>::iterator it = m_skinBools.begin();
1680   while (it != m_skinBools.end())
1681   {
1682     CStdString skinName = (*it).second.name;
1683     if (skinName.Left(currentSkin.size()) == currentSkin)
1684       (*it).second.value = false;
1685
1686     it++;
1687   }
1688   map<int, CSkinString>::iterator it2 = m_skinStrings.begin();
1689   while (it2 != m_skinStrings.end())
1690   {
1691     CStdString skinName = (*it2).second.name;
1692     if (skinName.Left(currentSkin.size()) == currentSkin)
1693       (*it2).second.value = "";
1694
1695     it2++;
1696   }
1697   g_infoManager.ResetCache();
1698 }
1699
1700 void CSettings::LoadUserFolderLayout()
1701 {
1702   // check them all
1703   CStdString strDir = g_guiSettings.GetString("system.playlistspath");
1704   if (strDir == "set default")
1705   {
1706     strDir = "special://profile/playlists/";
1707     g_guiSettings.SetString("system.playlistspath",strDir.c_str());
1708   }
1709   CDirectory::Create(strDir);
1710   CDirectory::Create(CUtil::AddFileToFolder(strDir,"music"));
1711   CDirectory::Create(CUtil::AddFileToFolder(strDir,"video"));
1712   CDirectory::Create(CUtil::AddFileToFolder(strDir,"mixed"));
1713 }
1714
1715 CStdString CSettings::GetProfileUserDataFolder() const
1716 {
1717   CStdString folder;
1718   if (m_iLastLoadedProfileIndex == 0)
1719     return GetUserDataFolder();
1720
1721   CUtil::AddFileToFolder(GetUserDataFolder(),m_vecProfiles[m_iLastLoadedProfileIndex].getDirectory(),folder);
1722
1723   return folder;
1724 }
1725
1726 CStdString CSettings::GetUserDataItem(const CStdString& strFile) const
1727 {
1728   CStdString folder;
1729   folder = "special://profile/"+strFile;
1730   if (!CFile::Exists(folder))
1731     folder = "special://masterprofile/"+strFile;
1732   return folder;
1733 }
1734
1735 CStdString CSettings::GetUserDataFolder() const
1736 {
1737   return m_vecProfiles[0].getDirectory();
1738 }
1739
1740 CStdString CSettings::GetDatabaseFolder() const
1741 {
1742   CStdString folder;
1743   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1744     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Database", folder);
1745   else
1746     CUtil::AddFileToFolder(GetUserDataFolder(), "Database", folder);
1747
1748   return folder;
1749 }
1750
1751 CStdString CSettings::GetCDDBFolder() const
1752 {
1753   CStdString folder;
1754   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1755     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Database/CDDB", folder);
1756   else
1757     CUtil::AddFileToFolder(GetUserDataFolder(), "Database/CDDB", folder);
1758
1759   return folder;
1760 }
1761
1762 CStdString CSettings::GetThumbnailsFolder() const
1763 {
1764   CStdString folder;
1765   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1766     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails", folder);
1767   else
1768     CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails", folder);
1769
1770   return folder;
1771 }
1772
1773 CStdString CSettings::GetMusicThumbFolder() const
1774 {
1775   CStdString folder;
1776   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1777     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music", folder);
1778   else
1779     CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music", folder);
1780
1781   return folder;
1782 }
1783
1784 CStdString CSettings::GetLastFMThumbFolder() const
1785 {
1786   CStdString folder;
1787   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1788     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music/LastFM", folder);
1789   else
1790     CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music/LastFM", folder);
1791
1792   return folder;
1793 }
1794
1795 CStdString CSettings::GetMusicArtistThumbFolder() const
1796 {
1797   CStdString folder;
1798   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1799     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music/Artists", folder);
1800   else
1801     CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music/Artists", folder);
1802
1803   return folder;
1804 }
1805
1806 CStdString CSettings::GetVideoThumbFolder() const
1807 {
1808   CStdString folder;
1809   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1810     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Video", folder);
1811   else
1812     CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Video", folder);
1813
1814   return folder;
1815 }
1816
1817 CStdString CSettings::GetVideoFanartFolder() const
1818 {
1819   CStdString folder;
1820   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1821     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Video/Fanart", folder);
1822   else
1823     CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Video/Fanart", folder);
1824
1825   return folder;
1826 }
1827
1828 CStdString CSettings::GetMusicFanartFolder() const
1829 {
1830   CStdString folder;
1831   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1832     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music/Fanart", folder);
1833   else
1834     CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music/Fanart", folder);
1835
1836   return folder;
1837 }
1838
1839 CStdString CSettings::GetBookmarksThumbFolder() const
1840 {
1841   CStdString folder;
1842   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1843     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Video/Bookmarks", folder);
1844   else
1845     CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Video/Bookmarks", folder);
1846
1847   return folder;
1848 }
1849
1850 CStdString CSettings::GetPicturesThumbFolder() const
1851 {
1852   CStdString folder;
1853   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1854     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Pictures", folder);
1855   else
1856     CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Pictures", folder);
1857
1858   return folder;
1859 }
1860
1861 CStdString CSettings::GetProgramsThumbFolder() const
1862 {
1863   CStdString folder;
1864   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1865     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Programs", folder);
1866   else
1867     CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Programs", folder);
1868
1869   return folder;
1870 }
1871
1872 CStdString CSettings::GetGameSaveThumbFolder() const
1873 {
1874   CStdString folder;
1875   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasDatabases())
1876     CUtil::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/GameSaves", folder);
1877   else
1878     CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails/GameSaves", folder);
1879
1880   return folder;
1881 }
1882
1883 CStdString CSettings::GetProfilesThumbFolder() const
1884 {
1885   CStdString folder;
1886   CUtil::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Profiles", folder);
1887
1888   return folder;
1889 }
1890
1891 CStdString CSettings::GetSourcesFile() const
1892 {
1893   CStdString folder;
1894   if (m_vecProfiles[m_iLastLoadedProfileIndex].hasSources())
1895     CUtil::AddFileToFolder(GetProfileUserDataFolder(),"sources.xml",folder);
1896   else
1897     CUtil::AddFileToFolder(GetUserDataFolder(),"sources.xml",folder);
1898
1899   return folder;
1900 }
1901
1902 CStdString CSettings::GetSkinFolder() const
1903 {
1904   CStdString folder;
1905
1906   // Get the Current Skin Path
1907   return GetSkinFolder(g_guiSettings.GetString("lookandfeel.skin"));
1908 }
1909
1910 CStdString CSettings::GetScriptsFolder() const
1911 {
1912   CStdString folder = "special://home/scripts";
1913
1914   if ( CDirectory::Exists(folder) )
1915     return folder;
1916
1917   folder = "special://xbmc/scripts";
1918   return folder;
1919 }
1920
1921 CStdString CSettings::GetSkinFolder(const CStdString &skinName) const
1922 {
1923   CStdString folder;
1924
1925   // Get the Current Skin Path
1926   CUtil::AddFileToFolder("special://home/skin/", skinName, folder);
1927   if ( ! CDirectory::Exists(folder) )
1928     CUtil::AddFileToFolder("special://xbmc/skin/", skinName, folder);
1929
1930   return folder;
1931 }
1932
1933 void CSettings::LoadRSSFeeds()
1934 {
1935   CStdString rssXML;
1936   rssXML = GetUserDataItem("RssFeeds.xml");
1937   TiXmlDocument rssDoc;
1938   if (!CFile::Exists(rssXML))
1939   { // set defaults, or assume no rss feeds??
1940     return;
1941   }
1942   if (!rssDoc.LoadFile(rssXML))
1943   {
1944     CLog::Log(LOGERROR, "Error loading %s, Line %d\n%s", rssXML.c_str(), rssDoc.ErrorRow(), rssDoc.ErrorDesc());
1945     return;
1946   }
1947
1948   TiXmlElement *pRootElement = rssDoc.RootElement();
1949   if (!pRootElement || strcmpi(pRootElement->Value(),"rssfeeds") != 0)
1950   {
1951     CLog::Log(LOGERROR, "Error loading %s, no <rssfeeds> node", rssXML.c_str());
1952     return;
1953   }
1954
1955   m_mapRssUrls.clear();
1956   TiXmlElement* pSet = pRootElement->FirstChildElement("set");
1957   while (pSet)
1958   {
1959     int iId;
1960     if (pSet->QueryIntAttribute("id", &iId) == TIXML_SUCCESS)
1961     {
1962       RssSet set;
1963       set.rtl = pSet->Attribute("rtl") && strcasecmp(pSet->Attribute("rtl"),"true")==0;
1964       TiXmlElement* pFeed = pSet->FirstChildElement("feed");
1965       while (pFeed)
1966       {
1967         int iInterval;
1968         if ( pFeed->QueryIntAttribute("updateinterval",&iInterval) != TIXML_SUCCESS)
1969         {
1970           iInterval=30; // default to 30 min
1971           CLog::Log(LOGDEBUG,"no interval set, default to 30!");
1972         }
1973         if (pFeed->FirstChild())
1974         {
1975           // TODO: UTF-8: Do these URLs need to be converted to UTF-8?
1976           //              What about the xml encoding?
1977           CStdString strUrl = pFeed->FirstChild()->Value();
1978           set.url.push_back(strUrl);
1979           set.interval.push_back(iInterval);
1980         }
1981         pFeed = pFeed->NextSiblingElement("feed");
1982       }
1983       m_mapRssUrls.insert(make_pair(iId,set));
1984     }
1985     else
1986       CLog::Log(LOGERROR,"found rss url set with no id in RssFeeds.xml, ignored");
1987
1988     pSet = pSet->NextSiblingElement("set");
1989   }
1990 }
1991
1992 CStdString CSettings::GetSettingsFile() const
1993 {
1994   CStdString settings;
1995   if (m_iLastLoadedProfileIndex == 0)
1996     settings = "special://masterprofile/guisettings.xml";
1997   else
1998     settings = "special://profile/guisettings.xml";
1999   return settings;
2000 }
2001
2002 void CSettings::CreateProfileFolders()
2003 {
2004   CDirectory::Create(GetDatabaseFolder());
2005   CDirectory::Create(GetCDDBFolder());
2006
2007   // Thumbnails/
2008   CDirectory::Create(GetThumbnailsFolder());
2009   CDirectory::Create(GetMusicThumbFolder());
2010   CDirectory::Create(GetMusicArtistThumbFolder());
2011   CDirectory::Create(GetLastFMThumbFolder());
2012   CDirectory::Create(GetVideoThumbFolder());
2013   CDirectory::Create(GetVideoFanartFolder());
2014   CDirectory::Create(GetMusicFanartFolder());
2015   CDirectory::Create(GetBookmarksThumbFolder());
2016   CDirectory::Create(GetProgramsThumbFolder());
2017   CDirectory::Create(GetPicturesThumbFolder());
2018   CLog::Log(LOGINFO, "thumbnails folder: %s", GetThumbnailsFolder().c_str());
2019   for (unsigned int hex=0; hex < 16; hex++)
2020   {
2021     CStdString strHex;
2022     strHex.Format("%x",hex);
2023     CDirectory::Create(CUtil::AddFileToFolder(GetPicturesThumbFolder(), strHex));
2024     CDirectory::Create(CUtil::AddFileToFolder(GetMusicThumbFolder(), strHex));
2025     CDirectory::Create(CUtil::AddFileToFolder(GetVideoThumbFolder(), strHex));
2026   }
2027   CDirectory::Create("special://profile/keymaps");
2028   CDirectory::Create("special://profile/visualisations");
2029 }