2 * Copyright (C) 2005-2008 Team XBMC
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)
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.
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
24 #include "AdvancedSettings.h"
25 #include "Application.h"
26 #include "input/KeyboardLayoutConfiguration.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"
46 #include "guilib/LocalizeStrings.h"
47 #include "utils/StringUtils.h"
48 #include "utils/SystemInfo.h"
50 #include "win32/WIN32Util.h"
52 #if defined(_LINUX) && defined(HAS_FILESYSTEM_SMB)
53 #include "filesystem/SMBDirectory.h"
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"
63 using namespace XFILE;
65 CSettings::CSettings(void)
69 void CSettings::Initialize()
72 vector<RESOLUTION_INFO>::iterator it = m_ResInfo.begin();
74 m_ResInfo.insert(it, RES_CUSTOM, res);
76 for (int i = RES_HDTV_1080i; i <= RES_PAL60_16x9; i++)
78 g_graphicsContext.ResetScreenParameters((RESOLUTION)i);
79 g_graphicsContext.ResetOverscan((RESOLUTION)i, m_ResInfo[i].Overscan);
82 m_videoStacking = false;
84 m_bMyMusicSongInfoInVis = true; // UNUSED - depreciated.
85 m_bMyMusicSongThumbInVis = false; // used for music info in vis screen
87 m_bMyMusicPlaylistRepeat = false;
88 m_bMyMusicPlaylistShuffle = false;
90 m_bMyVideoPlaylistRepeat = false;
91 m_bMyVideoPlaylistShuffle = false;
92 m_bMyVideoNavFlatten = false;
93 m_bStartVideoWindowed = false;
94 m_bAddonAutoUpdate = true;
95 m_bAddonNotifications = true;
98 m_dynamicRangeCompressionLevel = 0;
99 m_iPreMuteVolumeLevel = 0;
101 m_fZoomAmount = 1.0f;
102 m_fPixelRatio = 1.0f;
103 m_bNonLinStretch = false;
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";
113 CStdString logDir = getenv("HOME");
114 logDir += "/Library/Logs/";
115 m_logFolder = logDir;
117 m_logFolder = "special://home/"; // log file location
120 // defaults for scanning
121 m_bMyMusicIsScanning = false;
123 iAdditionalSubtitleDirectoryChecked = 0;
124 m_iMyMusicStartWindow = WINDOW_MUSIC_FILES;
125 m_iVideoStartWindow = WINDOW_VIDEO_FILES;
127 m_watchMode["movies"] = VIDEO_SHOW_ALL;
128 m_watchMode["tvshows"] = VIDEO_SHOW_ALL;
129 m_watchMode["musicvideos"] = VIDEO_SHOW_ALL;
131 m_iSystemTimeTotalUp = 0;
132 m_HttpApiBroadcastLevel = 0;
133 m_HttpApiBroadcastPort = 8278;
135 m_userAgent = g_sysinfo.GetUserAgent();
137 m_usingLoginScreen = false;
138 m_lastUsedProfile = 0;
139 m_currentProfile = 0;
142 m_activeKeyboardMapping = "default";
145 CSettings::~CSettings(void)
151 void CSettings::Save() const
153 if (g_application.m_bStop)
155 //don't save settings when we're busy stopping the application
156 //a lot of screens try to save settings on deinit and deinit is called
157 //for every screen when the application is stopping.
160 if (!SaveSettings(GetSettingsFile()))
162 CLog::Log(LOGERROR, "Unable to save settings to %s", GetSettingsFile().c_str());
166 bool CSettings::Reset()
168 CLog::Log(LOGINFO, "Resetting settings");
169 CFile::Delete(GetSettingsFile());
171 return LoadSettings(GetSettingsFile());
174 bool CSettings::Load()
176 CSpecialProtocol::SetProfilePath(GetProfileUserDataFolder());
177 CLog::Log(LOGNOTICE, "loading %s", GetSettingsFile().c_str());
178 if (!LoadSettings(GetSettingsFile()))
180 CLog::Log(LOGERROR, "Unable to load %s, creating new %s with default values", GetSettingsFile().c_str(), GetSettingsFile().c_str());
187 LoadUserFolderLayout();
192 VECSOURCES *CSettings::GetSourcesFromType(const CStdString &type)
194 if (type == "programs" || type == "myprograms")
195 return &m_programSources;
196 else if (type == "files")
197 return &m_fileSources;
198 else if (type == "music")
199 return &m_musicSources;
200 else if (type == "video")
201 return &m_videoSources;
202 else if (type == "pictures")
203 return &m_pictureSources;
208 CStdString CSettings::GetDefaultSourceFromType(const CStdString &type)
210 CStdString defaultShare;
211 if (type == "programs" || type == "myprograms")
212 defaultShare = m_defaultProgramSource;
213 else if (type == "files")
214 defaultShare = m_defaultFileSource;
215 else if (type == "music")
216 defaultShare = m_defaultMusicSource;
217 else if (type == "pictures")
218 defaultShare = m_defaultPictureSource;
222 void CSettings::GetSources(const TiXmlElement* pRootElement, const CStdString& strTagName, VECSOURCES& items, CStdString& strDefault)
224 //CLog::Log(LOGDEBUG, " Parsing <%s> tag", strTagName.c_str());
228 const TiXmlNode *pChild = pRootElement->FirstChild(strTagName.c_str());
231 pChild = pChild->FirstChild();
234 CStdString strValue = pChild->Value();
235 if (strValue == "source" || strValue == "bookmark") // "bookmark" left in for backwards compatibility
238 if (GetSource(strTagName, pChild, share))
240 items.push_back(share);
244 CLog::Log(LOGERROR, " Missing or invalid <name> and/or <path> in source");
248 if (strValue == "default")
250 const TiXmlNode *pValueNode = pChild->FirstChild();
253 const char* pszText = pChild->FirstChild()->Value();
254 if (strlen(pszText) > 0)
255 strDefault = pszText;
256 CLog::Log(LOGDEBUG, " Setting <default> source to : %s", strDefault.c_str());
259 pChild = pChild->NextSibling();
264 CLog::Log(LOGDEBUG, " <%s> tag is missing or sources.xml is malformed", strTagName.c_str());
268 bool CSettings::GetSource(const CStdString &category, const TiXmlNode *source, CMediaSource &share)
270 //CLog::Log(LOGDEBUG," ---- SOURCE START ----");
271 const TiXmlNode *pNodeName = source->FirstChild("name");
273 if (pNodeName && pNodeName->FirstChild())
275 strName = pNodeName->FirstChild()->Value();
276 //CLog::Log(LOGDEBUG," Found name: %s", strName.c_str());
278 // get multiple paths
279 vector<CStdString> vecPaths;
280 const TiXmlElement *pPathName = source->FirstChildElement("path");
283 if (pPathName->FirstChild())
286 pPathName->Attribute("pathversion", &pathVersion);
287 CStdString strPath = pPathName->FirstChild()->Value();
288 strPath = CSpecialProtocol::ReplaceOldPath(strPath, pathVersion);
289 // make sure there are no virtualpaths or stack paths defined in xboxmediacenter.xml
290 //CLog::Log(LOGDEBUG," Found path: %s", strPath.c_str());
291 if (!URIUtils::IsStack(strPath))
293 // translate special tags
294 if (!strPath.IsEmpty() && strPath.at(0) == '$')
296 CStdString strPathOld(strPath);
297 strPath = CUtil::TranslateSpecialSource(strPath);
298 if (!strPath.IsEmpty())
300 //CLog::Log(LOGDEBUG," -> Translated to path: %s", strPath.c_str());
304 //CLog::Log(LOGERROR," -> Skipping invalid token: %s", strPathOld.c_str());
305 pPathName = pPathName->NextSiblingElement("path");
309 URIUtils::AddSlashAtEnd(strPath);
310 vecPaths.push_back(strPath);
313 CLog::Log(LOGERROR," Invalid path type (%s) in source", strPath.c_str());
315 pPathName = pPathName->NextSiblingElement("path");
318 const TiXmlNode *pLockMode = source->FirstChild("lockmode");
319 const TiXmlNode *pLockCode = source->FirstChild("lockcode");
320 const TiXmlNode *pBadPwdCount = source->FirstChild("badpwdcount");
321 const TiXmlNode *pThumbnailNode = source->FirstChild("thumbnail");
323 if (!strName.IsEmpty() && vecPaths.size() > 0)
325 vector<CStdString> verifiedPaths;
326 // disallowed for files, or theres only a single path in the vector
327 if ((category.Equals("files")) || (vecPaths.size() == 1))
328 verifiedPaths.push_back(vecPaths[0]);
333 // validate the paths
334 for (int j = 0; j < (int)vecPaths.size(); ++j)
336 CURL url(vecPaths[j]);
337 CStdString protocol = url.GetProtocol();
338 bool bIsInvalid = false;
341 if (category.Equals("programs") || category.Equals("myprograms"))
343 // only allow HD and plugins
344 if (url.IsLocal() || protocol.Equals("plugin"))
345 verifiedPaths.push_back(vecPaths[j]);
350 // for others allow everything (if the user does something silly, we can't stop them)
352 verifiedPaths.push_back(vecPaths[j]);
356 CLog::Log(LOGERROR," Invalid path type (%s) for multipath source", vecPaths[j].c_str());
359 // no valid paths? skip to next source
360 if (verifiedPaths.size() == 0)
362 CLog::Log(LOGERROR," Missing or invalid <name> and/or <path> in source");
367 share.FromNameAndPaths(category, strName, verifiedPaths);
369 share.m_iBadPwdCount = 0;
372 share.m_iLockMode = LockType(atoi(pLockMode->FirstChild()->Value()));
373 share.m_iHasLock = 2;
378 if (pLockCode->FirstChild())
379 share.m_strLockCode = pLockCode->FirstChild()->Value();
384 if (pBadPwdCount->FirstChild())
385 share.m_iBadPwdCount = atoi( pBadPwdCount->FirstChild()->Value() );
390 if (pThumbnailNode->FirstChild())
391 share.m_strThumbnailImage = pThumbnailNode->FirstChild()->Value();
399 bool CSettings::GetPath(const TiXmlElement* pRootElement, const char *tagName, CStdString &strValue)
401 CStdString strDefault = strValue;
402 if (XMLUtils::GetPath(pRootElement, tagName, strValue))
404 // check for "-" for backward compatibility
405 if (!strValue.Equals("-"))
408 // tag doesn't exist - set default
409 strValue = strDefault;
413 bool CSettings::GetString(const TiXmlElement* pRootElement, const char *tagName, CStdString &strValue, const CStdString& strDefaultValue)
415 if (XMLUtils::GetString(pRootElement, tagName, strValue))
417 // check for "-" for backward compatibility
418 if (!strValue.Equals("-"))
421 // tag doesn't exist - set default
422 strValue = strDefaultValue;
426 bool CSettings::GetString(const TiXmlElement* pRootElement, const char *tagName, char *szValue, const CStdString& strDefaultValue)
429 bool ret = GetString(pRootElement, tagName, strValue, strDefaultValue);
431 strcpy(szValue, strValue.c_str());
435 bool CSettings::GetInteger(const TiXmlElement* pRootElement, const char *tagName, int& iValue, const int iDefault, const int iMin, const int iMax)
437 if (XMLUtils::GetInt(pRootElement, tagName, iValue, iMin, iMax))
444 bool CSettings::GetFloat(const TiXmlElement* pRootElement, const char *tagName, float& fValue, const float fDefault, const float fMin, const float fMax)
446 if (XMLUtils::GetFloat(pRootElement, tagName, fValue, fMin, fMax))
453 void CSettings::GetViewState(const TiXmlElement *pRootElement, const CStdString &strTagName, CViewState &viewState, SORT_METHOD defaultSort, int defaultView)
455 const TiXmlElement* pNode = pRootElement->FirstChildElement(strTagName);
458 viewState.m_sortMethod = defaultSort;
459 viewState.m_viewMode = defaultView;
462 GetInteger(pNode, "viewmode", viewState.m_viewMode, defaultView, DEFAULT_VIEW_LIST, DEFAULT_VIEW_MAX);
465 GetInteger(pNode, "sortmethod", sortMethod, defaultSort, SORT_METHOD_NONE, SORT_METHOD_MAX);
466 viewState.m_sortMethod = (SORT_METHOD)sortMethod;
469 GetInteger(pNode, "sortorder", sortOrder, SORT_ORDER_ASC, SORT_ORDER_NONE, SORT_ORDER_DESC);
470 viewState.m_sortOrder = (SORT_ORDER)sortOrder;
473 void CSettings::SetViewState(TiXmlNode *pRootNode, const CStdString &strTagName, const CViewState &viewState) const
475 TiXmlElement newElement(strTagName);
476 TiXmlNode *pNewNode = pRootNode->InsertEndChild(newElement);
479 XMLUtils::SetInt(pNewNode, "viewmode", viewState.m_viewMode);
480 XMLUtils::SetInt(pNewNode, "sortmethod", (int)viewState.m_sortMethod);
481 XMLUtils::SetInt(pNewNode, "sortorder", (int)viewState.m_sortOrder);
485 bool CSettings::LoadCalibration(const TiXmlElement* pRoot, const CStdString& strSettingsFile)
487 const TiXmlElement *pElement = pRoot->FirstChildElement("resolutions");
490 CLog::Log(LOGERROR, "%s Doesn't contain <resolutions>", strSettingsFile.c_str());
493 const TiXmlElement *pResolution = pElement->FirstChildElement("resolution");
496 // get the data for this resolution
498 XMLUtils::GetString(pResolution, "description", mode);
499 // find this resolution in our resolution vector
500 for (unsigned int res = 0; res < m_ResInfo.size(); res++)
502 if (res == RES_WINDOW)
505 if (m_ResInfo[res].strMode == mode)
506 { // found, read in the rest of the information for this item
507 const TiXmlElement *pOverscan = pResolution->FirstChildElement("overscan");
510 GetInteger(pOverscan, "left", m_ResInfo[res].Overscan.left, 0, -m_ResInfo[res].iWidth / 4, m_ResInfo[res].iWidth / 4);
511 GetInteger(pOverscan, "top", m_ResInfo[res].Overscan.top, 0, -m_ResInfo[res].iHeight / 4, m_ResInfo[res].iHeight / 4);
512 GetInteger(pOverscan, "right", m_ResInfo[res].Overscan.right, m_ResInfo[res].iWidth, m_ResInfo[res].iWidth / 2, m_ResInfo[res].iWidth*3 / 2);
513 GetInteger(pOverscan, "bottom", m_ResInfo[res].Overscan.bottom, m_ResInfo[res].iHeight, m_ResInfo[res].iHeight / 2, m_ResInfo[res].iHeight*3 / 2);
516 // get the appropriate "safe graphics area" = 10% for 4x3, 3.5% for 16x9
518 if (res == RES_PAL_4x3 || res == RES_NTSC_4x3 || res == RES_PAL60_4x3 || res == RES_HDTV_480p_4x3)
523 GetInteger(pResolution, "subtitles", m_ResInfo[res].iSubtitles, (int)((1 - fSafe)*m_ResInfo[res].iHeight), m_ResInfo[res].iHeight / 2, m_ResInfo[res].iHeight*5 / 4);
524 GetFloat(pResolution, "pixelratio", m_ResInfo[res].fPixelRatio, 128.0f / 117.0f, 0.5f, 2.0f);
525 /* CLog::Log(LOGDEBUG, " calibration for %s %ix%i", m_ResInfo[res].strMode, m_ResInfo[res].iWidth, m_ResInfo[res].iHeight);
526 CLog::Log(LOGDEBUG, " subtitle yposition:%i pixelratio:%03.3f offsets:(%i,%i)->(%i,%i)",
527 m_ResInfo[res].iSubtitles, m_ResInfo[res].fPixelRatio,
528 m_ResInfo[res].Overscan.left, m_ResInfo[res].Overscan.top,
529 m_ResInfo[res].Overscan.right, m_ResInfo[res].Overscan.bottom);*/
533 pResolution = pResolution->NextSiblingElement("resolution");
536 /* Hmm, these stuff shouldn't be releaded, they should be used instead of our internal
537 id counter to select what resolution is affected by this settings
539 const CStdString def("");
541 GetString(pResolution, "xrandrid", val, def);
542 strncpy(m_ResInfo[iRes].strId, val.c_str(), sizeof(m_ResInfo[iRes].strId));
543 GetString(pResolution, "output", val, def);
544 strncpy(m_ResInfo[iRes].strOutput, val.c_str(), sizeof(m_ResInfo[iRes].strOutput));
545 GetFloat(pResolution, "refreshrate", m_ResInfo[iRes].fRefreshRate, 0, 0, 200);
552 bool CSettings::SaveCalibration(TiXmlNode* pRootNode) const
554 TiXmlElement xmlRootElement("resolutions");
555 TiXmlNode *pRoot = pRootNode->InsertEndChild(xmlRootElement);
557 // save WINDOW, DESKTOP and CUSTOM resolution
558 for (size_t i = RES_WINDOW ; i < m_ResInfo.size() ; i++)
560 // Write the resolution tag
561 TiXmlElement resElement("resolution");
562 TiXmlNode *pNode = pRoot->InsertEndChild(resElement);
563 // Now write each of the pieces of information we need...
564 XMLUtils::SetString(pNode, "description", m_ResInfo[i].strMode);
565 XMLUtils::SetInt(pNode, "subtitles", m_ResInfo[i].iSubtitles);
566 XMLUtils::SetFloat(pNode, "pixelratio", m_ResInfo[i].fPixelRatio);
568 XMLUtils::SetFloat(pNode, "refreshrate", m_ResInfo[i].fRefreshRate);
569 XMLUtils::SetString(pNode, "output", m_ResInfo[i].strOutput);
570 XMLUtils::SetString(pNode, "xrandrid", m_ResInfo[i].strId);
572 // create the overscan child
573 TiXmlElement overscanElement("overscan");
574 TiXmlNode *pOverscanNode = pNode->InsertEndChild(overscanElement);
575 XMLUtils::SetInt(pOverscanNode, "left", m_ResInfo[i].Overscan.left);
576 XMLUtils::SetInt(pOverscanNode, "top", m_ResInfo[i].Overscan.top);
577 XMLUtils::SetInt(pOverscanNode, "right", m_ResInfo[i].Overscan.right);
578 XMLUtils::SetInt(pOverscanNode, "bottom", m_ResInfo[i].Overscan.bottom);
583 bool CSettings::LoadSettings(const CStdString& strSettingsFile)
586 TiXmlDocument xmlDoc;
588 if (!xmlDoc.LoadFile(strSettingsFile))
590 CLog::Log(LOGERROR, "%s, Line %d\n%s", strSettingsFile.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
594 TiXmlElement *pRootElement = xmlDoc.RootElement();
595 if (strcmpi(pRootElement->Value(), "settings") != 0)
597 CLog::Log(LOGERROR, "%s\nDoesn't contain <settings>", strSettingsFile.c_str());
602 TiXmlElement *pElement = pRootElement->FirstChildElement("mymusic");
605 TiXmlElement *pChild = pElement->FirstChildElement("playlist");
608 XMLUtils::GetBoolean(pChild, "repeat", m_bMyMusicPlaylistRepeat);
609 XMLUtils::GetBoolean(pChild, "shuffle", m_bMyMusicPlaylistShuffle);
611 // if the user happened to reboot in the middle of the scan we save this state
612 pChild = pElement->FirstChildElement("scanning");
615 XMLUtils::GetBoolean(pChild, "isscanning", m_bMyMusicIsScanning);
617 GetInteger(pElement, "startwindow", m_iMyMusicStartWindow, WINDOW_MUSIC_FILES, WINDOW_MUSIC_FILES, WINDOW_MUSIC_NAV); //501; view songs
618 XMLUtils::GetBoolean(pElement, "songinfoinvis", m_bMyMusicSongInfoInVis);
619 XMLUtils::GetBoolean(pElement, "songthumbinvis", m_bMyMusicSongThumbInVis);
620 GetPath(pElement, "defaultlibview", m_defaultMusicLibSource);
623 pElement = pRootElement->FirstChildElement("myvideos");
626 GetInteger(pElement, "startwindow", m_iVideoStartWindow, WINDOW_VIDEO_FILES, WINDOW_VIDEO_FILES, WINDOW_VIDEO_NAV);
627 XMLUtils::GetBoolean(pElement, "stackvideos", m_videoStacking);
629 // Read the watchmode settings for the various media views
630 GetInteger(pElement, "watchmodemovies", m_watchMode["movies"], VIDEO_SHOW_ALL, VIDEO_SHOW_ALL, VIDEO_SHOW_WATCHED);
631 GetInteger(pElement, "watchmodetvshows", m_watchMode["tvshows"], VIDEO_SHOW_ALL, VIDEO_SHOW_ALL, VIDEO_SHOW_WATCHED);
632 GetInteger(pElement, "watchmodemusicvideos", m_watchMode["musicvideos"], VIDEO_SHOW_ALL, VIDEO_SHOW_ALL, VIDEO_SHOW_WATCHED);
634 XMLUtils::GetBoolean(pElement, "flatten", m_bMyVideoNavFlatten);
636 TiXmlElement *pChild = pElement->FirstChildElement("playlist");
639 XMLUtils::GetBoolean(pChild, "repeat", m_bMyVideoPlaylistRepeat);
640 XMLUtils::GetBoolean(pChild, "shuffle", m_bMyVideoPlaylistShuffle);
644 pElement = pRootElement->FirstChildElement("viewstates");
647 GetViewState(pElement, "musicnavartists", m_viewStateMusicNavArtists);
648 GetViewState(pElement, "musicnavalbums", m_viewStateMusicNavAlbums);
649 GetViewState(pElement, "musicnavsongs", m_viewStateMusicNavSongs);
650 GetViewState(pElement, "musiclastfm", m_viewStateMusicLastFM);
651 GetViewState(pElement, "videonavactors", m_viewStateVideoNavActors);
652 GetViewState(pElement, "videonavyears", m_viewStateVideoNavYears);
653 GetViewState(pElement, "videonavgenres", m_viewStateVideoNavGenres);
654 GetViewState(pElement, "videonavtitles", m_viewStateVideoNavTitles);
655 GetViewState(pElement, "videonavepisodes", m_viewStateVideoNavEpisodes, SORT_METHOD_EPISODE);
656 GetViewState(pElement, "videonavtvshows", m_viewStateVideoNavTvShows);
657 GetViewState(pElement, "videonavseasons", m_viewStateVideoNavSeasons);
658 GetViewState(pElement, "videonavmusicvideos", m_viewStateVideoNavMusicVideos);
660 GetViewState(pElement, "programs", m_viewStatePrograms, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
661 GetViewState(pElement, "pictures", m_viewStatePictures, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
662 GetViewState(pElement, "videofiles", m_viewStateVideoFiles, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
663 GetViewState(pElement, "musicfiles", m_viewStateMusicFiles, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
667 pElement = pRootElement->FirstChildElement("general");
670 GetInteger(pElement, "systemtotaluptime", m_iSystemTimeTotalUp, 0, 0, INT_MAX);
671 GetInteger(pElement, "httpapibroadcastlevel", m_HttpApiBroadcastLevel, 0, 0, 255);
672 GetInteger(pElement, "httpapibroadcastport", m_HttpApiBroadcastPort, 8278, 1, 65535);
673 XMLUtils::GetBoolean(pElement, "addonautoupdate", m_bAddonAutoUpdate);
674 XMLUtils::GetBoolean(pElement, "addonnotifications", m_bAddonNotifications);
677 pElement = pRootElement->FirstChildElement("defaultvideosettings");
681 bool deinterlaceModePresent = GetInteger(pElement, "deinterlacemode", deinterlaceMode, VS_DEINTERLACEMODE_OFF, VS_DEINTERLACEMODE_OFF, VS_DEINTERLACEMODE_FORCE);
683 bool interlaceMethodPresent = GetInteger(pElement, "interlacemethod", interlaceMethod, VS_INTERLACEMETHOD_AUTO, VS_INTERLACEMETHOD_AUTO, VS_INTERLACEMETHOD_INVERSE_TELECINE);
684 // For smooth conversion of settings stored before the deinterlaceMode existed
685 if (!deinterlaceModePresent && interlaceMethodPresent)
687 if (interlaceMethod == VS_INTERLACEMETHOD_NONE)
689 deinterlaceMode = VS_DEINTERLACEMODE_OFF;
690 interlaceMethod = VS_INTERLACEMETHOD_AUTO;
692 else if (interlaceMethod == VS_INTERLACEMETHOD_AUTO)
694 deinterlaceMode = VS_DEINTERLACEMODE_AUTO;
698 deinterlaceMode = VS_DEINTERLACEMODE_FORCE;
701 m_defaultVideoSettings.m_DeinterlaceMode = (EDEINTERLACEMODE)deinterlaceMode;
702 m_defaultVideoSettings.m_InterlaceMethod = (EINTERLACEMETHOD)interlaceMethod;
704 GetInteger(pElement, "scalingmethod", scalingMethod, VS_SCALINGMETHOD_LINEAR, VS_SCALINGMETHOD_NEAREST, VS_SCALINGMETHOD_SPLINE36);
705 m_defaultVideoSettings.m_ScalingMethod = (ESCALINGMETHOD)scalingMethod;
707 GetInteger(pElement, "viewmode", m_defaultVideoSettings.m_ViewMode, VIEW_MODE_NORMAL, VIEW_MODE_NORMAL, VIEW_MODE_CUSTOM);
708 GetFloat(pElement, "zoomamount", m_defaultVideoSettings.m_CustomZoomAmount, 1.0f, 0.5f, 2.0f);
709 GetFloat(pElement, "pixelratio", m_defaultVideoSettings.m_CustomPixelRatio, 1.0f, 0.5f, 2.0f);
710 GetFloat(pElement, "verticalshift", m_defaultVideoSettings.m_CustomVerticalShift, 0.0f, -2.0f, 2.0f);
711 GetFloat(pElement, "volumeamplification", m_defaultVideoSettings.m_VolumeAmplification, VOLUME_DRC_MINIMUM * 0.01f, VOLUME_DRC_MINIMUM * 0.01f, VOLUME_DRC_MAXIMUM * 0.01f);
712 GetFloat(pElement, "noisereduction", m_defaultVideoSettings.m_NoiseReduction, 0.0f, 0.0f, 1.0f);
713 XMLUtils::GetBoolean(pElement, "postprocess", m_defaultVideoSettings.m_PostProcess);
714 GetFloat(pElement, "sharpness", m_defaultVideoSettings.m_Sharpness, 0.0f, -1.0f, 1.0f);
715 XMLUtils::GetBoolean(pElement, "outputtoallspeakers", m_defaultVideoSettings.m_OutputToAllSpeakers);
716 XMLUtils::GetBoolean(pElement, "showsubtitles", m_defaultVideoSettings.m_SubtitleOn);
717 GetFloat(pElement, "brightness", m_defaultVideoSettings.m_Brightness, 50, 0, 100);
718 GetFloat(pElement, "contrast", m_defaultVideoSettings.m_Contrast, 50, 0, 100);
719 GetFloat(pElement, "gamma", m_defaultVideoSettings.m_Gamma, 20, 0, 100);
720 GetFloat(pElement, "audiodelay", m_defaultVideoSettings.m_AudioDelay, 0.0f, -10.0f, 10.0f);
721 GetFloat(pElement, "subtitledelay", m_defaultVideoSettings.m_SubtitleDelay, 0.0f, -10.0f, 10.0f);
722 XMLUtils::GetBoolean(pElement, "autocrop", m_defaultVideoSettings.m_Crop);
723 XMLUtils::GetBoolean(pElement, "nonlinstretch", m_defaultVideoSettings.m_CustomNonLinStretch);
725 m_defaultVideoSettings.m_SubtitleCached = false;
728 pElement = pRootElement->FirstChildElement("audio");
731 GetInteger(pElement, "volumelevel", m_nVolumeLevel, VOLUME_MAXIMUM, VOLUME_MINIMUM, VOLUME_MAXIMUM);
732 GetInteger(pElement, "dynamicrangecompression", m_dynamicRangeCompressionLevel, VOLUME_DRC_MINIMUM, VOLUME_DRC_MINIMUM, VOLUME_DRC_MAXIMUM);
735 LoadCalibration(pRootElement, strSettingsFile);
736 g_guiSettings.LoadXML(pRootElement);
737 LoadSkinSettings(pRootElement);
739 // Configure the PlayerCoreFactory
740 LoadPlayerCoreFactorySettings("special://xbmc/system/playercorefactory.xml", true);
741 LoadPlayerCoreFactorySettings(GetUserDataItem("playercorefactory.xml"), false);
744 g_advancedSettings.Load();
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;
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());
755 // setup any logging...
756 if (g_guiSettings.GetBool("debug.showloginfo"))
758 g_advancedSettings.m_logLevel = std::max(g_advancedSettings.m_logLevelHint, LOG_LEVEL_DEBUG_FREEMEM);
759 CLog::SetLogLevel(g_advancedSettings.m_logLevel);
760 CLog::Log(LOGNOTICE, "Enabled debug logging due to GUI setting (%d)", g_advancedSettings.m_logLevel);
765 bool CSettings::LoadPlayerCoreFactorySettings(const CStdString& fileStr, bool clear)
767 CLog::Log(LOGNOTICE, "Loading player core factory settings from %s.", fileStr.c_str());
768 if (!CFile::Exists(fileStr))
769 { // tell the user it doesn't exist
770 CLog::Log(LOGNOTICE, "%s does not exist. Skipping.", fileStr.c_str());
774 TiXmlDocument playerCoreFactoryXML;
775 if (!playerCoreFactoryXML.LoadFile(fileStr))
777 CLog::Log(LOGERROR, "Error loading %s, Line %d (%s)", fileStr.c_str(), playerCoreFactoryXML.ErrorRow(), playerCoreFactoryXML.ErrorDesc());
781 return CPlayerCoreFactory::LoadConfiguration(playerCoreFactoryXML.RootElement(), clear);
784 bool CSettings::SaveSettings(const CStdString& strSettingsFile, CGUISettings *localSettings /* = NULL */) const
786 TiXmlDocument xmlDoc;
787 TiXmlElement xmlRootElement("settings");
788 TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
789 if (!pRoot) return false;
790 // write our tags one by one - just a big list for now (can be flashed up later)
793 TiXmlElement musicNode("mymusic");
794 TiXmlNode *pNode = pRoot->InsertEndChild(musicNode);
795 if (!pNode) return false;
797 TiXmlElement childNode("playlist");
798 TiXmlNode *pChild = pNode->InsertEndChild(childNode);
799 if (!pChild) return false;
800 XMLUtils::SetBoolean(pChild, "repeat", m_bMyMusicPlaylistRepeat);
801 XMLUtils::SetBoolean(pChild, "shuffle", m_bMyMusicPlaylistShuffle);
804 TiXmlElement childNode("scanning");
805 TiXmlNode *pChild = pNode->InsertEndChild(childNode);
806 if (!pChild) return false;
807 XMLUtils::SetBoolean(pChild, "isscanning", m_bMyMusicIsScanning);
810 XMLUtils::SetInt(pNode, "startwindow", m_iMyMusicStartWindow);
811 XMLUtils::SetBoolean(pNode, "songinfoinvis", m_bMyMusicSongInfoInVis);
812 XMLUtils::SetBoolean(pNode, "songthumbinvis", m_bMyMusicSongThumbInVis);
813 XMLUtils::SetPath(pNode, "defaultlibview", m_defaultMusicLibSource);
816 TiXmlElement videosNode("myvideos");
817 pNode = pRoot->InsertEndChild(videosNode);
818 if (!pNode) return false;
820 XMLUtils::SetInt(pNode, "startwindow", m_iVideoStartWindow);
822 XMLUtils::SetBoolean(pNode, "stackvideos", m_videoStacking);
824 XMLUtils::SetInt(pNode, "watchmodemovies", m_watchMode.find("movies")->second);
825 XMLUtils::SetInt(pNode, "watchmodetvshows", m_watchMode.find("tvshows")->second);
826 XMLUtils::SetInt(pNode, "watchmodemusicvideos", m_watchMode.find("musicvideos")->second);
828 XMLUtils::SetBoolean(pNode, "flatten", m_bMyVideoNavFlatten);
831 TiXmlElement childNode("playlist");
832 TiXmlNode *pChild = pNode->InsertEndChild(childNode);
833 if (!pChild) return false;
834 XMLUtils::SetBoolean(pChild, "repeat", m_bMyVideoPlaylistRepeat);
835 XMLUtils::SetBoolean(pChild, "shuffle", m_bMyVideoPlaylistShuffle);
839 TiXmlElement viewStateNode("viewstates");
840 pNode = pRoot->InsertEndChild(viewStateNode);
843 SetViewState(pNode, "musicnavartists", m_viewStateMusicNavArtists);
844 SetViewState(pNode, "musicnavalbums", m_viewStateMusicNavAlbums);
845 SetViewState(pNode, "musicnavsongs", m_viewStateMusicNavSongs);
846 SetViewState(pNode, "musiclastfm", m_viewStateMusicLastFM);
847 SetViewState(pNode, "videonavactors", m_viewStateVideoNavActors);
848 SetViewState(pNode, "videonavyears", m_viewStateVideoNavYears);
849 SetViewState(pNode, "videonavgenres", m_viewStateVideoNavGenres);
850 SetViewState(pNode, "videonavtitles", m_viewStateVideoNavTitles);
851 SetViewState(pNode, "videonavepisodes", m_viewStateVideoNavEpisodes);
852 SetViewState(pNode, "videonavseasons", m_viewStateVideoNavSeasons);
853 SetViewState(pNode, "videonavtvshows", m_viewStateVideoNavTvShows);
854 SetViewState(pNode, "videonavmusicvideos", m_viewStateVideoNavMusicVideos);
856 SetViewState(pNode, "programs", m_viewStatePrograms);
857 SetViewState(pNode, "pictures", m_viewStatePictures);
858 SetViewState(pNode, "videofiles", m_viewStateVideoFiles);
859 SetViewState(pNode, "musicfiles", m_viewStateMusicFiles);
863 TiXmlElement generalNode("general");
864 pNode = pRoot->InsertEndChild(generalNode);
865 if (!pNode) return false;
866 XMLUtils::SetInt(pNode, "systemtotaluptime", m_iSystemTimeTotalUp);
867 XMLUtils::SetInt(pNode, "httpapibroadcastport", m_HttpApiBroadcastPort);
868 XMLUtils::SetInt(pNode, "httpapibroadcastlevel", m_HttpApiBroadcastLevel);
869 XMLUtils::SetBoolean(pNode, "addonautoupdate", m_bAddonAutoUpdate);
870 XMLUtils::SetBoolean(pNode, "addonnotifications", m_bAddonNotifications);
872 // default video settings
873 TiXmlElement videoSettingsNode("defaultvideosettings");
874 pNode = pRoot->InsertEndChild(videoSettingsNode);
875 if (!pNode) return false;
876 XMLUtils::SetInt(pNode, "deinterlacemode", m_defaultVideoSettings.m_DeinterlaceMode);
877 XMLUtils::SetInt(pNode, "interlacemethod", m_defaultVideoSettings.m_InterlaceMethod);
878 XMLUtils::SetInt(pNode, "scalingmethod", m_defaultVideoSettings.m_ScalingMethod);
879 XMLUtils::SetFloat(pNode, "noisereduction", m_defaultVideoSettings.m_NoiseReduction);
880 XMLUtils::SetBoolean(pNode, "postprocess", m_defaultVideoSettings.m_PostProcess);
881 XMLUtils::SetFloat(pNode, "sharpness", m_defaultVideoSettings.m_Sharpness);
882 XMLUtils::SetInt(pNode, "viewmode", m_defaultVideoSettings.m_ViewMode);
883 XMLUtils::SetFloat(pNode, "zoomamount", m_defaultVideoSettings.m_CustomZoomAmount);
884 XMLUtils::SetFloat(pNode, "pixelratio", m_defaultVideoSettings.m_CustomPixelRatio);
885 XMLUtils::SetFloat(pNode, "verticalshift", m_defaultVideoSettings.m_CustomVerticalShift);
886 XMLUtils::SetFloat(pNode, "volumeamplification", m_defaultVideoSettings.m_VolumeAmplification);
887 XMLUtils::SetBoolean(pNode, "outputtoallspeakers", m_defaultVideoSettings.m_OutputToAllSpeakers);
888 XMLUtils::SetBoolean(pNode, "showsubtitles", m_defaultVideoSettings.m_SubtitleOn);
889 XMLUtils::SetFloat(pNode, "brightness", m_defaultVideoSettings.m_Brightness);
890 XMLUtils::SetFloat(pNode, "contrast", m_defaultVideoSettings.m_Contrast);
891 XMLUtils::SetFloat(pNode, "gamma", m_defaultVideoSettings.m_Gamma);
892 XMLUtils::SetFloat(pNode, "audiodelay", m_defaultVideoSettings.m_AudioDelay);
893 XMLUtils::SetFloat(pNode, "subtitledelay", m_defaultVideoSettings.m_SubtitleDelay);
894 XMLUtils::SetBoolean(pNode, "autocrop", m_defaultVideoSettings.m_Crop);
895 XMLUtils::SetBoolean(pNode, "nonlinstretch", m_defaultVideoSettings.m_CustomNonLinStretch);
899 TiXmlElement volumeNode("audio");
900 pNode = pRoot->InsertEndChild(volumeNode);
901 if (!pNode) return false;
902 XMLUtils::SetInt(pNode, "volumelevel", m_nVolumeLevel);
903 XMLUtils::SetInt(pNode, "dynamicrangecompression", m_dynamicRangeCompressionLevel);
905 SaveCalibration(pRoot);
907 if (localSettings) // local settings to save
908 localSettings->SaveXML(pRoot);
909 else // save the global settings
910 g_guiSettings.SaveXML(pRoot);
912 SaveSkinSettings(pRoot);
915 SaveProfiles( PROFILES_FILE );
918 return xmlDoc.SaveFile(strSettingsFile);
921 bool CSettings::LoadProfile(unsigned int index)
923 unsigned int oldProfile = m_currentProfile;
924 m_currentProfile = index;
925 CStdString strOldSkin = g_guiSettings.GetString("lookandfeel.skin");
926 CStdString strOldFont = g_guiSettings.GetString("lookandfeel.font");
927 CStdString strOldTheme = g_guiSettings.GetString("lookandfeel.skintheme");
928 CStdString strOldColors = g_guiSettings.GetString("lookandfeel.skincolors");
931 CreateProfileFolders();
933 // initialize our charset converter
934 g_charsetConverter.reset();
936 // Load the langinfo to have user charset <-> utf-8 conversion
937 CStdString strLanguage = g_guiSettings.GetString("locale.language");
938 strLanguage[0] = toupper(strLanguage[0]);
940 CStdString strLangInfoPath;
941 strLangInfoPath.Format("special://xbmc/language/%s/langinfo.xml", strLanguage.c_str());
942 CLog::Log(LOGINFO, "load language info file:%s", strLangInfoPath.c_str());
943 g_langInfo.Load(strLangInfoPath);
945 CStdString strLanguagePath;
946 strLanguagePath.Format("special://xbmc/language/%s/strings.xml", strLanguage.c_str());
948 CButtonTranslator::GetInstance().Load();
949 g_localizeStrings.Load(strLanguagePath);
951 g_Mouse.SetEnabled(g_guiSettings.GetBool("input.enablemouse"));
953 g_infoManager.ResetCache();
954 g_infoManager.ResetLibraryBools();
956 // always reload the skin - we need it for the new language strings
957 g_application.ReloadSkin();
959 if (m_currentProfile != 0)
962 if (doc.LoadFile(URIUtils::AddFileToFolder(GetUserDataFolder(),"guisettings.xml")))
963 g_guiSettings.LoadMasterLock(doc.RootElement());
966 CPasswordManager::GetInstance().Clear();
968 // to set labels - shares are reloaded
969 #if !defined(_WIN32) && defined(HAS_DVD_DRIVE)
970 MEDIA_DETECT::CDetectDVDMedia::UpdateState();
973 CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_WINDOW_RESET);
974 g_windowManager.SendMessage(msg);
976 CUtil::DeleteMusicDatabaseDirectoryCache();
977 CUtil::DeleteVideoDatabaseDirectoryCache();
979 ADDON::CAddonMgr::Get().StartServices(false);
984 m_currentProfile = oldProfile;
989 bool CSettings::DeleteProfile(unsigned int index)
991 const CProfile *profile = GetProfile(index);
995 CGUIDialogYesNo* dlgYesNo = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
999 CStdString str = g_localizeStrings.Get(13201);
1000 message.Format(str.c_str(), profile->getName());
1001 dlgYesNo->SetHeading(13200);
1002 dlgYesNo->SetLine(0, message);
1003 dlgYesNo->SetLine(1, "");
1004 dlgYesNo->SetLine(2, "");
1005 dlgYesNo->DoModal();
1007 if (dlgYesNo->IsConfirmed())
1010 CStdString strDirectory = profile->getDirectory();
1011 m_vecProfiles.erase(m_vecProfiles.begin()+index);
1012 if (index == m_currentProfile)
1018 CFileItemPtr item = CFileItemPtr(new CFileItem(URIUtils::AddFileToFolder(GetUserDataFolder(), strDirectory)));
1019 item->SetPath(URIUtils::AddFileToFolder(GetUserDataFolder(), strDirectory + "/"));
1020 item->m_bIsFolder = true;
1022 CFileUtils::DeleteItem(item);
1028 SaveProfiles( PROFILES_FILE );
1033 void CSettings::LoadProfiles(const CStdString& profilesFile)
1035 // clear out our profiles
1036 m_vecProfiles.clear();
1038 TiXmlDocument profilesDoc;
1039 if (CFile::Exists(profilesFile))
1041 if (profilesDoc.LoadFile(profilesFile))
1043 TiXmlElement *rootElement = profilesDoc.RootElement();
1044 if (rootElement && strcmpi(rootElement->Value(),"profiles") == 0)
1046 XMLUtils::GetUInt(rootElement, "lastloaded", m_lastUsedProfile);
1047 XMLUtils::GetBoolean(rootElement, "useloginscreen", m_usingLoginScreen);
1048 XMLUtils::GetInt(rootElement, "nextIdProfile", m_nextIdProfile);
1050 TiXmlElement* pProfile = rootElement->FirstChildElement("profile");
1052 CStdString defaultDir("special://home/userdata");
1053 if (!CDirectory::Exists(defaultDir))
1054 defaultDir = "special://xbmc/userdata";
1057 CProfile profile(defaultDir);
1058 profile.Load(pProfile,GetNextProfileId());
1059 AddProfile(profile);
1060 pProfile = pProfile->NextSiblingElement("profile");
1064 CLog::Log(LOGERROR, "Error loading %s, no <profiles> node", profilesFile.c_str());
1067 CLog::Log(LOGERROR, "Error loading %s, Line %d\n%s", profilesFile.c_str(), profilesDoc.ErrorRow(), profilesDoc.ErrorDesc());
1070 if (m_vecProfiles.empty())
1071 { // add the master user
1072 CProfile profile("special://masterprofile/", "Master user",0);
1073 AddProfile(profile);
1076 // check the validity of the previous profile index
1077 if (m_lastUsedProfile >= m_vecProfiles.size())
1078 m_lastUsedProfile = 0;
1080 m_currentProfile = m_lastUsedProfile;
1082 // the login screen runs as the master profile, so if we're using this, we need to ensure
1083 // we switch to the master profile
1084 if (m_usingLoginScreen)
1085 m_currentProfile = 0;
1088 bool CSettings::SaveProfiles(const CStdString& profilesFile) const
1090 TiXmlDocument xmlDoc;
1091 TiXmlElement xmlRootElement("profiles");
1092 TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
1093 if (!pRoot) return false;
1094 XMLUtils::SetInt(pRoot,"lastloaded", m_currentProfile);
1095 XMLUtils::SetBoolean(pRoot,"useloginscreen",m_usingLoginScreen);
1096 XMLUtils::SetInt(pRoot,"nextIdProfile",m_nextIdProfile);
1097 for (unsigned int i = 0; i < m_vecProfiles.size(); ++i)
1098 m_vecProfiles[i].Save(pRoot);
1101 return xmlDoc.SaveFile(profilesFile);
1104 bool CSettings::LoadUPnPXml(const CStdString& strSettingsFile)
1106 TiXmlDocument UPnPDoc;
1108 if (!CFile::Exists(strSettingsFile))
1109 { // set defaults, or assume no rss feeds??
1112 if (!UPnPDoc.LoadFile(strSettingsFile))
1114 CLog::Log(LOGERROR, "Error loading %s, Line %d\n%s", strSettingsFile.c_str(), UPnPDoc.ErrorRow(), UPnPDoc.ErrorDesc());
1118 TiXmlElement *pRootElement = UPnPDoc.RootElement();
1119 if (!pRootElement || strcmpi(pRootElement->Value(),"upnpserver") != 0)
1121 CLog::Log(LOGERROR, "Error loading %s, no <upnpserver> node", strSettingsFile.c_str());
1126 // default values for ports
1127 m_UPnPPortServer = 0;
1128 m_UPnPPortRenderer = 0;
1129 m_UPnPMaxReturnedItems = 0;
1131 XMLUtils::GetString(pRootElement, "UUID", m_UPnPUUIDServer);
1132 XMLUtils::GetInt(pRootElement, "Port", m_UPnPPortServer);
1133 XMLUtils::GetInt(pRootElement, "MaxReturnedItems", m_UPnPMaxReturnedItems);
1134 XMLUtils::GetString(pRootElement, "UUIDRenderer", m_UPnPUUIDRenderer);
1135 XMLUtils::GetInt(pRootElement, "PortRenderer", m_UPnPPortRenderer);
1140 bool CSettings::SaveUPnPXml(const CStdString& strSettingsFile) const
1142 TiXmlDocument xmlDoc;
1143 TiXmlElement xmlRootElement("upnpserver");
1144 TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
1145 if (!pRoot) return false;
1147 // create a new Element for UUID
1148 XMLUtils::SetString(pRoot, "UUID", m_UPnPUUIDServer);
1149 XMLUtils::SetInt(pRoot, "Port", m_UPnPPortServer);
1150 XMLUtils::SetInt(pRoot, "MaxReturnedItems", m_UPnPMaxReturnedItems);
1151 XMLUtils::SetString(pRoot, "UUIDRenderer", m_UPnPUUIDRenderer);
1152 XMLUtils::SetInt(pRoot, "PortRenderer", m_UPnPPortRenderer);
1155 return xmlDoc.SaveFile(strSettingsFile);
1158 bool CSettings::UpdateShare(const CStdString &type, const CStdString oldName, const CMediaSource &share)
1160 VECSOURCES *pShares = GetSourcesFromType(type);
1162 if (!pShares) return false;
1164 // update our current share list
1165 CMediaSource* pShare=NULL;
1166 for (IVECSOURCES it = pShares->begin(); it != pShares->end(); it++)
1168 if ((*it).strName == oldName)
1170 (*it).strName = share.strName;
1171 (*it).strPath = share.strPath;
1172 (*it).vecPaths = share.vecPaths;
1181 // Update our XML file as well
1182 return SaveSources();
1185 // NOTE: This function does NOT save the sources.xml file - you need to call SaveSources() separately.
1186 bool CSettings::UpdateSource(const CStdString &strType, const CStdString strOldName, const CStdString &strUpdateElement, const CStdString &strUpdateText)
1188 VECSOURCES *pShares = GetSourcesFromType(strType);
1190 if (!pShares) return false;
1192 for (IVECSOURCES it = pShares->begin(); it != pShares->end(); it++)
1194 if ((*it).strName == strOldName)
1196 if ("name" == strUpdateElement)
1197 (*it).strName = strUpdateText;
1198 else if ("lockmode" == strUpdateElement)
1199 (*it).m_iLockMode = LockType(atoi(strUpdateText));
1200 else if ("lockcode" == strUpdateElement)
1201 (*it).m_strLockCode = strUpdateText;
1202 else if ("badpwdcount" == strUpdateElement)
1203 (*it).m_iBadPwdCount = atoi(strUpdateText);
1204 else if ("thumbnail" == strUpdateElement)
1205 (*it).m_strThumbnailImage = strUpdateText;
1206 else if ("path" == strUpdateElement)
1208 (*it).vecPaths.clear();
1209 (*it).strPath = strUpdateText;
1210 (*it).vecPaths.push_back(strUpdateText);
1220 bool CSettings::DeleteSource(const CStdString &strType, const CStdString strName, const CStdString strPath, bool virtualSource)
1222 VECSOURCES *pShares = GetSourcesFromType(strType);
1223 if (!pShares) return false;
1227 for (IVECSOURCES it = pShares->begin(); it != pShares->end(); it++)
1229 if ((*it).strName == strName && (*it).strPath == strPath)
1231 CLog::Log(LOGDEBUG,"found share, removing!");
1241 return SaveSources();
1244 bool CSettings::AddShare(const CStdString &type, const CMediaSource &share)
1246 VECSOURCES *pShares = GetSourcesFromType(type);
1247 if (!pShares) return false;
1249 // translate dir and add to our current shares
1250 CStdString strPath1 = share.strPath;
1252 if(strPath1.IsEmpty())
1254 CLog::Log(LOGERROR, "unable to add empty path");
1258 CMediaSource shareToAdd = share;
1259 if (strPath1.at(0) == '$')
1261 shareToAdd.strPath = CUtil::TranslateSpecialSource(strPath1);
1262 if (!share.strPath.IsEmpty())
1263 CLog::Log(LOGDEBUG, "%s Translated (%s) to Path (%s)",__FUNCTION__ ,strPath1.c_str(),shareToAdd.strPath.c_str());
1266 CLog::Log(LOGDEBUG, "%s Skipping invalid special directory token: %s",__FUNCTION__,strPath1.c_str());
1270 pShares->push_back(shareToAdd);
1272 if (!share.m_ignore)
1274 return SaveSources();
1279 bool CSettings::SaveSources()
1281 // TODO: Should we be specifying utf8 here??
1283 TiXmlElement xmlRootElement("sources");
1284 TiXmlNode *pRoot = doc.InsertEndChild(xmlRootElement);
1285 if (!pRoot) return false;
1287 // ok, now run through and save each sources section
1288 SetSources(pRoot, "programs", m_programSources, m_defaultProgramSource);
1289 SetSources(pRoot, "video", m_videoSources, "");
1290 SetSources(pRoot, "music", m_musicSources, m_defaultMusicSource);
1291 SetSources(pRoot, "pictures", m_pictureSources, m_defaultPictureSource);
1292 SetSources(pRoot, "files", m_fileSources, m_defaultFileSource);
1294 return doc.SaveFile(GetSourcesFile());
1297 bool CSettings::SetSources(TiXmlNode *root, const char *section, const VECSOURCES &shares, const char *defaultPath)
1299 TiXmlElement sectionElement(section);
1300 TiXmlNode *sectionNode = root->InsertEndChild(sectionElement);
1303 XMLUtils::SetPath(sectionNode, "default", defaultPath);
1304 for (unsigned int i = 0; i < shares.size(); i++)
1306 const CMediaSource &share = shares[i];
1309 TiXmlElement source("source");
1311 XMLUtils::SetString(&source, "name", share.strName);
1313 for (unsigned int i = 0; i < share.vecPaths.size(); i++)
1314 XMLUtils::SetPath(&source, "path", share.vecPaths[i]);
1316 if (share.m_iHasLock)
1318 XMLUtils::SetInt(&source, "lockmode", share.m_iLockMode);
1319 XMLUtils::SetString(&source, "lockcode", share.m_strLockCode);
1320 XMLUtils::SetInt(&source, "badpwdcount", share.m_iBadPwdCount);
1322 if (!share.m_strThumbnailImage.IsEmpty())
1323 XMLUtils::SetPath(&source, "thumbnail", share.m_strThumbnailImage);
1325 sectionNode->InsertEndChild(source);
1331 void CSettings::LoadSources()
1334 m_fileSources.clear();
1335 m_musicSources.clear();
1336 m_pictureSources.clear();
1337 m_programSources.clear();
1338 m_videoSources.clear();
1340 CStdString strSourcesFile = GetSourcesFile();
1341 CLog::Log(LOGNOTICE, "Loading media sources from %s", strSourcesFile.c_str());
1344 TiXmlDocument xmlDoc;
1345 TiXmlElement *pRootElement = NULL;
1346 if (xmlDoc.LoadFile(strSourcesFile))
1348 pRootElement = xmlDoc.RootElement();
1349 if (pRootElement && strcmpi(pRootElement->Value(),"sources") != 0)
1350 CLog::Log(LOGERROR, "%s sources.xml file does not contain <sources>", __FUNCTION__);
1352 else if (CFile::Exists(strSourcesFile))
1353 CLog::Log(LOGERROR, "%s Error loading %s: Line %d, %s", __FUNCTION__, strSourcesFile.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
1359 GetSources(pRootElement, "programs", m_programSources, m_defaultProgramSource);
1360 GetSources(pRootElement, "pictures", m_pictureSources, m_defaultPictureSource);
1361 GetSources(pRootElement, "files", m_fileSources, m_defaultFileSource);
1362 GetSources(pRootElement, "music", m_musicSources, m_defaultMusicSource);
1363 GetSources(pRootElement, "video", m_videoSources, dummy);
1367 void CSettings::LoadSkinSettings(const TiXmlElement* pRootElement)
1370 const TiXmlElement *pElement = pRootElement->FirstChildElement("skinsettings");
1373 m_skinStrings.clear();
1374 m_skinBools.clear();
1375 const TiXmlElement *pChild = pElement->FirstChildElement("setting");
1378 CStdString settingName = pChild->Attribute("name");
1379 if (pChild->Attribute("type") && strcmpi(pChild->Attribute("type"),"string") == 0)
1382 string.name = settingName;
1383 string.value = pChild->FirstChild() ? pChild->FirstChild()->Value() : "";
1384 m_skinStrings.insert(pair<int, CSkinString>(number++, string));
1389 setting.name = settingName;
1390 setting.value = pChild->FirstChild() ? strcmpi(pChild->FirstChild()->Value(), "true") == 0 : false;
1391 m_skinBools.insert(pair<int, CSkinBool>(number++, setting));
1393 pChild = pChild->NextSiblingElement("setting");
1398 void CSettings::SaveSkinSettings(TiXmlNode *pRootElement) const
1400 // add the <skinsettings> tag
1401 TiXmlElement xmlSettingsElement("skinsettings");
1402 TiXmlNode *pSettingsNode = pRootElement->InsertEndChild(xmlSettingsElement);
1403 if (!pSettingsNode) return;
1404 for (map<int, CSkinBool>::const_iterator it = m_skinBools.begin(); it != m_skinBools.end(); ++it)
1406 // Add a <setting type="bool" name="name">true/false</setting>
1407 TiXmlElement xmlSetting("setting");
1408 xmlSetting.SetAttribute("type", "bool");
1409 xmlSetting.SetAttribute("name", (*it).second.name.c_str());
1410 TiXmlText xmlBool((*it).second.value ? "true" : "false");
1411 xmlSetting.InsertEndChild(xmlBool);
1412 pSettingsNode->InsertEndChild(xmlSetting);
1414 for (map<int, CSkinString>::const_iterator it = m_skinStrings.begin(); it != m_skinStrings.end(); ++it)
1416 // Add a <setting type="string" name="name">string</setting>
1417 TiXmlElement xmlSetting("setting");
1418 xmlSetting.SetAttribute("type", "string");
1419 xmlSetting.SetAttribute("name", (*it).second.name.c_str());
1420 TiXmlText xmlLabel((*it).second.value);
1421 xmlSetting.InsertEndChild(xmlLabel);
1422 pSettingsNode->InsertEndChild(xmlSetting);
1426 void CSettings::Clear()
1428 m_programSources.clear();
1429 m_pictureSources.clear();
1430 m_fileSources.clear();
1431 m_musicSources.clear();
1432 m_videoSources.clear();
1433 // m_vecIcons.clear();
1434 m_vecProfiles.clear();
1435 m_mapRssUrls.clear();
1436 m_skinBools.clear();
1437 m_skinStrings.clear();
1440 int CSettings::TranslateSkinString(const CStdString &setting)
1442 CStdString settingName;
1443 settingName.Format("%s.%s", g_guiSettings.GetString("lookandfeel.skin").c_str(), setting);
1444 // run through and see if we have this setting
1445 for (map<int, CSkinString>::const_iterator it = m_skinStrings.begin(); it != m_skinStrings.end(); it++)
1447 if (settingName.Equals((*it).second.name))
1450 // didn't find it - insert it
1451 CSkinString skinString;
1452 skinString.name = settingName;
1453 m_skinStrings.insert(pair<int, CSkinString>(m_skinStrings.size() + m_skinBools.size(), skinString));
1454 return m_skinStrings.size() + m_skinBools.size() - 1;
1457 const CStdString &CSettings::GetSkinString(int setting) const
1459 map<int, CSkinString>::const_iterator it = m_skinStrings.find(setting);
1460 if (it != m_skinStrings.end())
1462 return (*it).second.value;
1464 return StringUtils::EmptyString;
1467 void CSettings::SetSkinString(int setting, const CStdString &label)
1469 map<int, CSkinString>::iterator it = m_skinStrings.find(setting);
1470 if (it != m_skinStrings.end())
1472 (*it).second.value = label;
1476 CLog::Log(LOGFATAL, "%s : Unknown setting requested", __FUNCTION__);
1479 void CSettings::ResetSkinSetting(const CStdString &setting)
1481 CStdString settingName;
1482 settingName.Format("%s.%s", g_guiSettings.GetString("lookandfeel.skin").c_str(), setting);
1483 // run through and see if we have this setting as a string
1484 for (map<int, CSkinString>::iterator it = m_skinStrings.begin(); it != m_skinStrings.end(); it++)
1486 if (settingName.Equals((*it).second.name))
1488 (*it).second.value = "";
1492 // and now check for the skin bool
1493 for (map<int, CSkinBool>::iterator it = m_skinBools.begin(); it != m_skinBools.end(); it++)
1495 if (settingName.Equals((*it).second.name))
1497 (*it).second.value = false;
1503 int CSettings::TranslateSkinBool(const CStdString &setting)
1505 CStdString settingName;
1506 settingName.Format("%s.%s", g_guiSettings.GetString("lookandfeel.skin").c_str(), setting);
1507 // run through and see if we have this setting
1508 for (map<int, CSkinBool>::const_iterator it = m_skinBools.begin(); it != m_skinBools.end(); it++)
1510 if (settingName.Equals((*it).second.name))
1513 // didn't find it - insert it
1515 skinBool.name = settingName;
1516 skinBool.value = false;
1517 m_skinBools.insert(pair<int, CSkinBool>(m_skinBools.size() + m_skinStrings.size(), skinBool));
1518 return m_skinBools.size() + m_skinStrings.size() - 1;
1521 bool CSettings::GetSkinBool(int setting) const
1523 map<int, CSkinBool>::const_iterator it = m_skinBools.find(setting);
1524 if (it != m_skinBools.end())
1526 return (*it).second.value;
1528 // default is to return false
1532 void CSettings::SetSkinBool(int setting, bool set)
1534 map<int, CSkinBool>::iterator it = m_skinBools.find(setting);
1535 if (it != m_skinBools.end())
1537 (*it).second.value = set;
1541 CLog::Log(LOGFATAL,"%s : Unknown setting requested", __FUNCTION__);
1544 void CSettings::ResetSkinSettings()
1546 CStdString currentSkin = g_guiSettings.GetString("lookandfeel.skin") + ".";
1547 // clear all the settings and strings from this skin.
1548 map<int, CSkinBool>::iterator it = m_skinBools.begin();
1549 while (it != m_skinBools.end())
1551 CStdString skinName = (*it).second.name;
1552 if (skinName.Left(currentSkin.size()) == currentSkin)
1553 (*it).second.value = false;
1557 map<int, CSkinString>::iterator it2 = m_skinStrings.begin();
1558 while (it2 != m_skinStrings.end())
1560 CStdString skinName = (*it2).second.name;
1561 if (skinName.Left(currentSkin.size()) == currentSkin)
1562 (*it2).second.value = "";
1566 g_infoManager.ResetCache();
1569 static CStdString ToWatchContent(const CStdString &content)
1571 if (content == "seasons" || content == "episodes")
1577 int CSettings::GetWatchMode(const CStdString& content) const
1579 std::map<CStdString, int>::iterator it = g_settings.m_watchMode.find(ToWatchContent(content));
1580 if (it != g_settings.m_watchMode.end())
1582 return VIDEO_SHOW_ALL;
1585 void CSettings::SetWatchMode(const CStdString& content, int value)
1587 std::map<CStdString, int>::iterator it = g_settings.m_watchMode.find(ToWatchContent(content));
1588 if (it != g_settings.m_watchMode.end())
1592 void CSettings::CycleWatchMode(const CStdString& content)
1594 std::map<CStdString, int>::iterator it = g_settings.m_watchMode.find(ToWatchContent(content));
1595 if (it != g_settings.m_watchMode.end())
1598 if (it->second > VIDEO_SHOW_WATCHED)
1599 it->second = VIDEO_SHOW_ALL;
1603 void CSettings::LoadUserFolderLayout()
1606 CStdString strDir = g_guiSettings.GetString("system.playlistspath");
1607 if (strDir == "set default")
1609 strDir = "special://profile/playlists/";
1610 g_guiSettings.SetString("system.playlistspath",strDir.c_str());
1612 CDirectory::Create(strDir);
1613 CDirectory::Create(URIUtils::AddFileToFolder(strDir,"music"));
1614 CDirectory::Create(URIUtils::AddFileToFolder(strDir,"video"));
1615 CDirectory::Create(URIUtils::AddFileToFolder(strDir,"mixed"));
1618 CStdString CSettings::GetProfileUserDataFolder() const
1621 if (m_currentProfile == 0)
1622 return GetUserDataFolder();
1624 URIUtils::AddFileToFolder(GetUserDataFolder(),GetCurrentProfile().getDirectory(),folder);
1629 CStdString CSettings::GetUserDataItem(const CStdString& strFile) const
1632 folder = "special://profile/"+strFile;
1633 //check if item exists in the profile
1634 //(either for folder or for a file (depending on slashAtEnd of strFile)
1635 //otherwise return path to masterprofile
1636 if ( (URIUtils::HasSlashAtEnd(folder) && !CDirectory::Exists(folder)) || !CFile::Exists(folder))
1637 folder = "special://masterprofile/"+strFile;
1641 CStdString CSettings::GetUserDataFolder() const
1643 return GetMasterProfile().getDirectory();
1646 CStdString CSettings::GetDatabaseFolder() const
1649 if (GetCurrentProfile().hasDatabases())
1650 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Database", folder);
1652 URIUtils::AddFileToFolder(GetUserDataFolder(), "Database", folder);
1657 CStdString CSettings::GetCDDBFolder() const
1660 if (GetCurrentProfile().hasDatabases())
1661 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Database/CDDB", folder);
1663 URIUtils::AddFileToFolder(GetUserDataFolder(), "Database/CDDB", folder);
1668 CStdString CSettings::GetThumbnailsFolder() const
1671 if (GetCurrentProfile().hasDatabases())
1672 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails", folder);
1674 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails", folder);
1679 CStdString CSettings::GetMusicThumbFolder() const
1682 if (GetCurrentProfile().hasDatabases())
1683 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music", folder);
1685 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music", folder);
1690 CStdString CSettings::GetLastFMThumbFolder() const
1693 if (GetCurrentProfile().hasDatabases())
1694 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music/LastFM", folder);
1696 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music/LastFM", folder);
1701 CStdString CSettings::GetMusicArtistThumbFolder() const
1704 if (GetCurrentProfile().hasDatabases())
1705 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music/Artists", folder);
1707 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music/Artists", folder);
1712 CStdString CSettings::GetVideoThumbFolder() const
1715 if (GetCurrentProfile().hasDatabases())
1716 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Video", folder);
1718 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Video", folder);
1723 CStdString CSettings::GetVideoFanartFolder() const
1726 if (GetCurrentProfile().hasDatabases())
1727 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Video/Fanart", folder);
1729 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Video/Fanart", folder);
1734 CStdString CSettings::GetMusicFanartFolder() const
1737 if (GetCurrentProfile().hasDatabases())
1738 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music/Fanart", folder);
1740 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music/Fanart", folder);
1745 CStdString CSettings::GetBookmarksThumbFolder() const
1748 if (GetCurrentProfile().hasDatabases())
1749 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Video/Bookmarks", folder);
1751 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Video/Bookmarks", folder);
1756 CStdString CSettings::GetSourcesFile() const
1759 if (GetCurrentProfile().hasSources())
1760 URIUtils::AddFileToFolder(GetProfileUserDataFolder(),"sources.xml",folder);
1762 URIUtils::AddFileToFolder(GetUserDataFolder(),"sources.xml",folder);
1767 void CSettings::LoadRSSFeeds()
1770 rssXML = GetUserDataItem("RssFeeds.xml");
1771 TiXmlDocument rssDoc;
1772 if (!CFile::Exists(rssXML))
1773 { // set defaults, or assume no rss feeds??
1776 if (!rssDoc.LoadFile(rssXML))
1778 CLog::Log(LOGERROR, "Error loading %s, Line %d\n%s", rssXML.c_str(), rssDoc.ErrorRow(), rssDoc.ErrorDesc());
1782 TiXmlElement *pRootElement = rssDoc.RootElement();
1783 if (!pRootElement || strcmpi(pRootElement->Value(),"rssfeeds") != 0)
1785 CLog::Log(LOGERROR, "Error loading %s, no <rssfeeds> node", rssXML.c_str());
1789 m_mapRssUrls.clear();
1790 TiXmlElement* pSet = pRootElement->FirstChildElement("set");
1794 if (pSet->QueryIntAttribute("id", &iId) == TIXML_SUCCESS)
1797 set.rtl = pSet->Attribute("rtl") && strcasecmp(pSet->Attribute("rtl"),"true")==0;
1798 TiXmlElement* pFeed = pSet->FirstChildElement("feed");
1802 if ( pFeed->QueryIntAttribute("updateinterval",&iInterval) != TIXML_SUCCESS)
1804 iInterval=30; // default to 30 min
1805 CLog::Log(LOGDEBUG,"no interval set, default to 30!");
1807 if (pFeed->FirstChild())
1809 // TODO: UTF-8: Do these URLs need to be converted to UTF-8?
1810 // What about the xml encoding?
1811 CStdString strUrl = pFeed->FirstChild()->Value();
1812 set.url.push_back(strUrl);
1813 set.interval.push_back(iInterval);
1815 pFeed = pFeed->NextSiblingElement("feed");
1817 m_mapRssUrls.insert(make_pair(iId,set));
1820 CLog::Log(LOGERROR,"found rss url set with no id in RssFeeds.xml, ignored");
1822 pSet = pSet->NextSiblingElement("set");
1826 CStdString CSettings::GetSettingsFile() const
1828 CStdString settings;
1829 if (m_currentProfile == 0)
1830 settings = "special://masterprofile/guisettings.xml";
1832 settings = "special://profile/guisettings.xml";
1836 void CSettings::CreateProfileFolders()
1838 CDirectory::Create(GetDatabaseFolder());
1839 CDirectory::Create(GetCDDBFolder());
1842 CDirectory::Create(GetThumbnailsFolder());
1843 CDirectory::Create(GetMusicThumbFolder());
1844 CDirectory::Create(GetMusicArtistThumbFolder());
1845 CDirectory::Create(GetLastFMThumbFolder());
1846 CDirectory::Create(GetVideoThumbFolder());
1847 CDirectory::Create(GetVideoFanartFolder());
1848 CDirectory::Create(GetMusicFanartFolder());
1849 CDirectory::Create(GetBookmarksThumbFolder());
1850 CStdString generatedThumbsFolder = URIUtils::AddFileToFolder(GetThumbnailsFolder(), "generated");
1851 CDirectory::Create(generatedThumbsFolder);
1852 CLog::Log(LOGINFO, "thumbnails folder: %s", GetThumbnailsFolder().c_str());
1853 for (unsigned int hex=0; hex < 16; hex++)
1856 strHex.Format("%x",hex);
1857 CDirectory::Create(URIUtils::AddFileToFolder(GetMusicThumbFolder(), strHex));
1858 CDirectory::Create(URIUtils::AddFileToFolder(GetVideoThumbFolder(), strHex));
1859 CDirectory::Create(URIUtils::AddFileToFolder(GetThumbnailsFolder(), strHex));
1860 CDirectory::Create(URIUtils::AddFileToFolder(generatedThumbsFolder, strHex));
1862 CDirectory::Create("special://profile/addon_data");
1863 CDirectory::Create("special://profile/keymaps");
1866 static CProfile emptyProfile;
1868 const CProfile &CSettings::GetMasterProfile() const
1870 if (GetNumProfiles())
1871 return m_vecProfiles[0];
1872 CLog::Log(LOGERROR, "%s - master profile requested while none exists", __FUNCTION__);
1873 return emptyProfile;
1876 const CProfile &CSettings::GetCurrentProfile() const
1878 if (m_currentProfile < m_vecProfiles.size())
1879 return m_vecProfiles[m_currentProfile];
1880 CLog::Log(LOGERROR, "%s - last profile index (%u) is outside the valid range (%" PRIdS ")", __FUNCTION__, m_currentProfile, m_vecProfiles.size());
1881 return emptyProfile;
1884 int CSettings::GetCurrentProfileId() const
1886 return GetCurrentProfile().getId();
1889 void CSettings::UpdateCurrentProfileDate()
1891 if (m_currentProfile < m_vecProfiles.size())
1892 m_vecProfiles[m_currentProfile].setDate();
1895 const CProfile *CSettings::GetProfile(unsigned int index) const
1897 if (index < GetNumProfiles())
1898 return &m_vecProfiles[index];
1902 CProfile *CSettings::GetProfile(unsigned int index)
1904 if (index < GetNumProfiles())
1905 return &m_vecProfiles[index];
1909 unsigned int CSettings::GetNumProfiles() const
1911 return m_vecProfiles.size();
1914 int CSettings::GetProfileIndex(const CStdString &name) const
1916 for (unsigned int i = 0; i < m_vecProfiles.size(); i++)
1917 if (m_vecProfiles[i].getName().Equals(name))
1922 void CSettings::AddProfile(const CProfile &profile)
1924 //data integrity check - covers off migration from old profiles.xml, incrementing of the m_nextIdProfile,and bad data coming in
1925 m_nextIdProfile = max(m_nextIdProfile, profile.getId() + 1);
1927 m_vecProfiles.push_back(profile);
1930 void CSettings::LoadMasterForLogin()
1932 // save the previous user
1933 m_lastUsedProfile = m_currentProfile;
1934 if (m_currentProfile != 0)