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