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