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