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;
143 CSettings::~CSettings(void)
149 void CSettings::Save() const
151 if (g_application.m_bStop)
153 //don't save settings when we're busy stopping the application
154 //a lot of screens try to save settings on deinit and deinit is called
155 //for every screen when the application is stopping.
158 if (!SaveSettings(GetSettingsFile()))
160 CLog::Log(LOGERROR, "Unable to save settings to %s", GetSettingsFile().c_str());
164 bool CSettings::Reset()
166 CLog::Log(LOGINFO, "Resetting settings");
167 CFile::Delete(GetSettingsFile());
169 return LoadSettings(GetSettingsFile());
172 bool CSettings::Load()
174 CSpecialProtocol::SetProfilePath(GetProfileUserDataFolder());
175 CLog::Log(LOGNOTICE, "loading %s", GetSettingsFile().c_str());
176 if (!LoadSettings(GetSettingsFile()))
178 CLog::Log(LOGERROR, "Unable to load %s, creating new %s with default values", GetSettingsFile().c_str(), GetSettingsFile().c_str());
185 LoadUserFolderLayout();
190 VECSOURCES *CSettings::GetSourcesFromType(const CStdString &type)
192 if (type == "programs" || type == "myprograms")
193 return &m_programSources;
194 else if (type == "files")
195 return &m_fileSources;
196 else if (type == "music")
197 return &m_musicSources;
198 else if (type == "video")
199 return &m_videoSources;
200 else if (type == "pictures")
201 return &m_pictureSources;
206 CStdString CSettings::GetDefaultSourceFromType(const CStdString &type)
208 CStdString defaultShare;
209 if (type == "programs" || type == "myprograms")
210 defaultShare = m_defaultProgramSource;
211 else if (type == "files")
212 defaultShare = m_defaultFileSource;
213 else if (type == "music")
214 defaultShare = m_defaultMusicSource;
215 else if (type == "pictures")
216 defaultShare = m_defaultPictureSource;
220 void CSettings::GetSources(const TiXmlElement* pRootElement, const CStdString& strTagName, VECSOURCES& items, CStdString& strDefault)
222 //CLog::Log(LOGDEBUG, " Parsing <%s> tag", strTagName.c_str());
226 const TiXmlNode *pChild = pRootElement->FirstChild(strTagName.c_str());
229 pChild = pChild->FirstChild();
232 CStdString strValue = pChild->Value();
233 if (strValue == "source" || strValue == "bookmark") // "bookmark" left in for backwards compatibility
236 if (GetSource(strTagName, pChild, share))
238 items.push_back(share);
242 CLog::Log(LOGERROR, " Missing or invalid <name> and/or <path> in source");
246 if (strValue == "default")
248 const TiXmlNode *pValueNode = pChild->FirstChild();
251 const char* pszText = pChild->FirstChild()->Value();
252 if (strlen(pszText) > 0)
253 strDefault = pszText;
254 CLog::Log(LOGDEBUG, " Setting <default> source to : %s", strDefault.c_str());
257 pChild = pChild->NextSibling();
262 CLog::Log(LOGDEBUG, " <%s> tag is missing or sources.xml is malformed", strTagName.c_str());
266 bool CSettings::GetSource(const CStdString &category, const TiXmlNode *source, CMediaSource &share)
268 //CLog::Log(LOGDEBUG," ---- SOURCE START ----");
269 const TiXmlNode *pNodeName = source->FirstChild("name");
271 if (pNodeName && pNodeName->FirstChild())
273 strName = pNodeName->FirstChild()->Value();
274 //CLog::Log(LOGDEBUG," Found name: %s", strName.c_str());
276 // get multiple paths
277 vector<CStdString> vecPaths;
278 const TiXmlElement *pPathName = source->FirstChildElement("path");
281 if (pPathName->FirstChild())
284 pPathName->Attribute("pathversion", &pathVersion);
285 CStdString strPath = pPathName->FirstChild()->Value();
286 strPath = CSpecialProtocol::ReplaceOldPath(strPath, pathVersion);
287 // make sure there are no virtualpaths or stack paths defined in xboxmediacenter.xml
288 //CLog::Log(LOGDEBUG," Found path: %s", strPath.c_str());
289 if (!URIUtils::IsStack(strPath))
291 // translate special tags
292 if (!strPath.IsEmpty() && strPath.at(0) == '$')
294 CStdString strPathOld(strPath);
295 strPath = CUtil::TranslateSpecialSource(strPath);
296 if (!strPath.IsEmpty())
298 //CLog::Log(LOGDEBUG," -> Translated to path: %s", strPath.c_str());
302 //CLog::Log(LOGERROR," -> Skipping invalid token: %s", strPathOld.c_str());
303 pPathName = pPathName->NextSiblingElement("path");
307 URIUtils::AddSlashAtEnd(strPath);
308 vecPaths.push_back(strPath);
311 CLog::Log(LOGERROR," Invalid path type (%s) in source", strPath.c_str());
313 pPathName = pPathName->NextSiblingElement("path");
316 const TiXmlNode *pLockMode = source->FirstChild("lockmode");
317 const TiXmlNode *pLockCode = source->FirstChild("lockcode");
318 const TiXmlNode *pBadPwdCount = source->FirstChild("badpwdcount");
319 const TiXmlNode *pThumbnailNode = source->FirstChild("thumbnail");
321 if (!strName.IsEmpty() && vecPaths.size() > 0)
323 vector<CStdString> verifiedPaths;
324 // disallowed for files, or theres only a single path in the vector
325 if ((category.Equals("files")) || (vecPaths.size() == 1))
326 verifiedPaths.push_back(vecPaths[0]);
331 // validate the paths
332 for (int j = 0; j < (int)vecPaths.size(); ++j)
334 CURL url(vecPaths[j]);
335 CStdString protocol = url.GetProtocol();
336 bool bIsInvalid = false;
339 if (category.Equals("programs") || category.Equals("myprograms"))
341 // only allow HD and plugins
342 if (url.IsLocal() || protocol.Equals("plugin"))
343 verifiedPaths.push_back(vecPaths[j]);
348 // for others allow everything (if the user does something silly, we can't stop them)
350 verifiedPaths.push_back(vecPaths[j]);
354 CLog::Log(LOGERROR," Invalid path type (%s) for multipath source", vecPaths[j].c_str());
357 // no valid paths? skip to next source
358 if (verifiedPaths.size() == 0)
360 CLog::Log(LOGERROR," Missing or invalid <name> and/or <path> in source");
365 share.FromNameAndPaths(category, strName, verifiedPaths);
367 share.m_iBadPwdCount = 0;
370 share.m_iLockMode = LockType(atoi(pLockMode->FirstChild()->Value()));
371 share.m_iHasLock = 2;
376 if (pLockCode->FirstChild())
377 share.m_strLockCode = pLockCode->FirstChild()->Value();
382 if (pBadPwdCount->FirstChild())
383 share.m_iBadPwdCount = atoi( pBadPwdCount->FirstChild()->Value() );
388 if (pThumbnailNode->FirstChild())
389 share.m_strThumbnailImage = pThumbnailNode->FirstChild()->Value();
397 bool CSettings::GetPath(const TiXmlElement* pRootElement, const char *tagName, CStdString &strValue)
399 CStdString strDefault = strValue;
400 if (XMLUtils::GetPath(pRootElement, tagName, strValue))
402 // check for "-" for backward compatibility
403 if (!strValue.Equals("-"))
406 // tag doesn't exist - set default
407 strValue = strDefault;
411 bool CSettings::GetString(const TiXmlElement* pRootElement, const char *tagName, CStdString &strValue, const CStdString& strDefaultValue)
413 if (XMLUtils::GetString(pRootElement, tagName, strValue))
415 // check for "-" for backward compatibility
416 if (!strValue.Equals("-"))
419 // tag doesn't exist - set default
420 strValue = strDefaultValue;
424 bool CSettings::GetString(const TiXmlElement* pRootElement, const char *tagName, char *szValue, const CStdString& strDefaultValue)
427 bool ret = GetString(pRootElement, tagName, strValue, strDefaultValue);
429 strcpy(szValue, strValue.c_str());
433 bool CSettings::GetInteger(const TiXmlElement* pRootElement, const char *tagName, int& iValue, const int iDefault, const int iMin, const int iMax)
435 if (XMLUtils::GetInt(pRootElement, tagName, iValue, iMin, iMax))
442 bool CSettings::GetFloat(const TiXmlElement* pRootElement, const char *tagName, float& fValue, const float fDefault, const float fMin, const float fMax)
444 if (XMLUtils::GetFloat(pRootElement, tagName, fValue, fMin, fMax))
451 void CSettings::GetViewState(const TiXmlElement *pRootElement, const CStdString &strTagName, CViewState &viewState, SORT_METHOD defaultSort, int defaultView)
453 const TiXmlElement* pNode = pRootElement->FirstChildElement(strTagName);
456 viewState.m_sortMethod = defaultSort;
457 viewState.m_viewMode = defaultView;
460 GetInteger(pNode, "viewmode", viewState.m_viewMode, defaultView, DEFAULT_VIEW_LIST, DEFAULT_VIEW_MAX);
463 GetInteger(pNode, "sortmethod", sortMethod, defaultSort, SORT_METHOD_NONE, SORT_METHOD_MAX);
464 viewState.m_sortMethod = (SORT_METHOD)sortMethod;
467 GetInteger(pNode, "sortorder", sortOrder, SORT_ORDER_ASC, SORT_ORDER_NONE, SORT_ORDER_DESC);
468 viewState.m_sortOrder = (SORT_ORDER)sortOrder;
471 void CSettings::SetViewState(TiXmlNode *pRootNode, const CStdString &strTagName, const CViewState &viewState) const
473 TiXmlElement newElement(strTagName);
474 TiXmlNode *pNewNode = pRootNode->InsertEndChild(newElement);
477 XMLUtils::SetInt(pNewNode, "viewmode", viewState.m_viewMode);
478 XMLUtils::SetInt(pNewNode, "sortmethod", (int)viewState.m_sortMethod);
479 XMLUtils::SetInt(pNewNode, "sortorder", (int)viewState.m_sortOrder);
483 bool CSettings::LoadCalibration(const TiXmlElement* pRoot, const CStdString& strSettingsFile)
485 const TiXmlElement *pElement = pRoot->FirstChildElement("resolutions");
488 CLog::Log(LOGERROR, "%s Doesn't contain <resolutions>", strSettingsFile.c_str());
491 const TiXmlElement *pResolution = pElement->FirstChildElement("resolution");
494 // get the data for this resolution
496 XMLUtils::GetString(pResolution, "description", mode);
497 // find this resolution in our resolution vector
498 for (unsigned int res = 0; res < m_ResInfo.size(); res++)
500 if (res == RES_WINDOW)
503 if (m_ResInfo[res].strMode == mode)
504 { // found, read in the rest of the information for this item
505 const TiXmlElement *pOverscan = pResolution->FirstChildElement("overscan");
508 GetInteger(pOverscan, "left", m_ResInfo[res].Overscan.left, 0, -m_ResInfo[res].iWidth / 4, m_ResInfo[res].iWidth / 4);
509 GetInteger(pOverscan, "top", m_ResInfo[res].Overscan.top, 0, -m_ResInfo[res].iHeight / 4, m_ResInfo[res].iHeight / 4);
510 GetInteger(pOverscan, "right", m_ResInfo[res].Overscan.right, m_ResInfo[res].iWidth, m_ResInfo[res].iWidth / 2, m_ResInfo[res].iWidth*3 / 2);
511 GetInteger(pOverscan, "bottom", m_ResInfo[res].Overscan.bottom, m_ResInfo[res].iHeight, m_ResInfo[res].iHeight / 2, m_ResInfo[res].iHeight*3 / 2);
514 // get the appropriate "safe graphics area" = 10% for 4x3, 3.5% for 16x9
516 if (res == RES_PAL_4x3 || res == RES_NTSC_4x3 || res == RES_PAL60_4x3 || res == RES_HDTV_480p_4x3)
521 GetInteger(pResolution, "subtitles", m_ResInfo[res].iSubtitles, (int)((1 - fSafe)*m_ResInfo[res].iHeight), m_ResInfo[res].iHeight / 2, m_ResInfo[res].iHeight*5 / 4);
522 GetFloat(pResolution, "pixelratio", m_ResInfo[res].fPixelRatio, 128.0f / 117.0f, 0.5f, 2.0f);
523 /* CLog::Log(LOGDEBUG, " calibration for %s %ix%i", m_ResInfo[res].strMode, m_ResInfo[res].iWidth, m_ResInfo[res].iHeight);
524 CLog::Log(LOGDEBUG, " subtitle yposition:%i pixelratio:%03.3f offsets:(%i,%i)->(%i,%i)",
525 m_ResInfo[res].iSubtitles, m_ResInfo[res].fPixelRatio,
526 m_ResInfo[res].Overscan.left, m_ResInfo[res].Overscan.top,
527 m_ResInfo[res].Overscan.right, m_ResInfo[res].Overscan.bottom);*/
531 pResolution = pResolution->NextSiblingElement("resolution");
534 /* Hmm, these stuff shouldn't be releaded, they should be used instead of our internal
535 id counter to select what resolution is affected by this settings
537 const CStdString def("");
539 GetString(pResolution, "xrandrid", val, def);
540 strncpy(m_ResInfo[iRes].strId, val.c_str(), sizeof(m_ResInfo[iRes].strId));
541 GetString(pResolution, "output", val, def);
542 strncpy(m_ResInfo[iRes].strOutput, val.c_str(), sizeof(m_ResInfo[iRes].strOutput));
543 GetFloat(pResolution, "refreshrate", m_ResInfo[iRes].fRefreshRate, 0, 0, 200);
550 bool CSettings::SaveCalibration(TiXmlNode* pRootNode) const
552 TiXmlElement xmlRootElement("resolutions");
553 TiXmlNode *pRoot = pRootNode->InsertEndChild(xmlRootElement);
555 // save WINDOW, DESKTOP and CUSTOM resolution
556 for (size_t i = RES_WINDOW ; i < m_ResInfo.size() ; i++)
558 // Write the resolution tag
559 TiXmlElement resElement("resolution");
560 TiXmlNode *pNode = pRoot->InsertEndChild(resElement);
561 // Now write each of the pieces of information we need...
562 XMLUtils::SetString(pNode, "description", m_ResInfo[i].strMode);
563 XMLUtils::SetInt(pNode, "subtitles", m_ResInfo[i].iSubtitles);
564 XMLUtils::SetFloat(pNode, "pixelratio", m_ResInfo[i].fPixelRatio);
566 XMLUtils::SetFloat(pNode, "refreshrate", m_ResInfo[i].fRefreshRate);
567 XMLUtils::SetString(pNode, "output", m_ResInfo[i].strOutput);
568 XMLUtils::SetString(pNode, "xrandrid", m_ResInfo[i].strId);
570 // create the overscan child
571 TiXmlElement overscanElement("overscan");
572 TiXmlNode *pOverscanNode = pNode->InsertEndChild(overscanElement);
573 XMLUtils::SetInt(pOverscanNode, "left", m_ResInfo[i].Overscan.left);
574 XMLUtils::SetInt(pOverscanNode, "top", m_ResInfo[i].Overscan.top);
575 XMLUtils::SetInt(pOverscanNode, "right", m_ResInfo[i].Overscan.right);
576 XMLUtils::SetInt(pOverscanNode, "bottom", m_ResInfo[i].Overscan.bottom);
581 bool CSettings::LoadSettings(const CStdString& strSettingsFile)
584 TiXmlDocument xmlDoc;
586 if (!xmlDoc.LoadFile(strSettingsFile))
588 CLog::Log(LOGERROR, "%s, Line %d\n%s", strSettingsFile.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
592 TiXmlElement *pRootElement = xmlDoc.RootElement();
593 if (strcmpi(pRootElement->Value(), "settings") != 0)
595 CLog::Log(LOGERROR, "%s\nDoesn't contain <settings>", strSettingsFile.c_str());
600 TiXmlElement *pElement = pRootElement->FirstChildElement("mymusic");
603 TiXmlElement *pChild = pElement->FirstChildElement("playlist");
606 XMLUtils::GetBoolean(pChild, "repeat", m_bMyMusicPlaylistRepeat);
607 XMLUtils::GetBoolean(pChild, "shuffle", m_bMyMusicPlaylistShuffle);
609 // if the user happened to reboot in the middle of the scan we save this state
610 pChild = pElement->FirstChildElement("scanning");
613 XMLUtils::GetBoolean(pChild, "isscanning", m_bMyMusicIsScanning);
615 GetInteger(pElement, "startwindow", m_iMyMusicStartWindow, WINDOW_MUSIC_FILES, WINDOW_MUSIC_FILES, WINDOW_MUSIC_NAV); //501; view songs
616 XMLUtils::GetBoolean(pElement, "songinfoinvis", m_bMyMusicSongInfoInVis);
617 XMLUtils::GetBoolean(pElement, "songthumbinvis", m_bMyMusicSongThumbInVis);
618 GetPath(pElement, "defaultlibview", m_defaultMusicLibSource);
621 pElement = pRootElement->FirstChildElement("myvideos");
624 GetInteger(pElement, "startwindow", m_iVideoStartWindow, WINDOW_VIDEO_FILES, WINDOW_VIDEO_FILES, WINDOW_VIDEO_NAV);
625 XMLUtils::GetBoolean(pElement, "stackvideos", m_videoStacking);
627 // Read the watchmode settings for the various media views
628 GetInteger(pElement, "watchmodemovies", m_watchMode["movies"], VIDEO_SHOW_ALL, VIDEO_SHOW_ALL, VIDEO_SHOW_WATCHED);
629 GetInteger(pElement, "watchmodetvshows", m_watchMode["tvshows"], VIDEO_SHOW_ALL, VIDEO_SHOW_ALL, VIDEO_SHOW_WATCHED);
630 GetInteger(pElement, "watchmodemusicvideos", m_watchMode["musicvideos"], VIDEO_SHOW_ALL, VIDEO_SHOW_ALL, VIDEO_SHOW_WATCHED);
632 XMLUtils::GetBoolean(pElement, "flatten", m_bMyVideoNavFlatten);
634 TiXmlElement *pChild = pElement->FirstChildElement("playlist");
637 XMLUtils::GetBoolean(pChild, "repeat", m_bMyVideoPlaylistRepeat);
638 XMLUtils::GetBoolean(pChild, "shuffle", m_bMyVideoPlaylistShuffle);
642 pElement = pRootElement->FirstChildElement("viewstates");
645 GetViewState(pElement, "musicnavartists", m_viewStateMusicNavArtists);
646 GetViewState(pElement, "musicnavalbums", m_viewStateMusicNavAlbums);
647 GetViewState(pElement, "musicnavsongs", m_viewStateMusicNavSongs);
648 GetViewState(pElement, "musiclastfm", m_viewStateMusicLastFM);
649 GetViewState(pElement, "videonavactors", m_viewStateVideoNavActors);
650 GetViewState(pElement, "videonavyears", m_viewStateVideoNavYears);
651 GetViewState(pElement, "videonavgenres", m_viewStateVideoNavGenres);
652 GetViewState(pElement, "videonavtitles", m_viewStateVideoNavTitles);
653 GetViewState(pElement, "videonavepisodes", m_viewStateVideoNavEpisodes, SORT_METHOD_EPISODE);
654 GetViewState(pElement, "videonavtvshows", m_viewStateVideoNavTvShows);
655 GetViewState(pElement, "videonavseasons", m_viewStateVideoNavSeasons);
656 GetViewState(pElement, "videonavmusicvideos", m_viewStateVideoNavMusicVideos);
658 GetViewState(pElement, "programs", m_viewStatePrograms, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
659 GetViewState(pElement, "pictures", m_viewStatePictures, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
660 GetViewState(pElement, "videofiles", m_viewStateVideoFiles, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
661 GetViewState(pElement, "musicfiles", m_viewStateMusicFiles, SORT_METHOD_LABEL, DEFAULT_VIEW_AUTO);
665 pElement = pRootElement->FirstChildElement("general");
668 GetInteger(pElement, "systemtotaluptime", m_iSystemTimeTotalUp, 0, 0, INT_MAX);
669 GetInteger(pElement, "httpapibroadcastlevel", m_HttpApiBroadcastLevel, 0, 0, 255);
670 GetInteger(pElement, "httpapibroadcastport", m_HttpApiBroadcastPort, 8278, 1, 65535);
671 XMLUtils::GetBoolean(pElement, "addonautoupdate", m_bAddonAutoUpdate);
672 XMLUtils::GetBoolean(pElement, "addonnotifications", m_bAddonNotifications);
675 pElement = pRootElement->FirstChildElement("defaultvideosettings");
679 bool deinterlaceModePresent = GetInteger(pElement, "deinterlacemode", deinterlaceMode, VS_DEINTERLACEMODE_OFF, VS_DEINTERLACEMODE_OFF, VS_DEINTERLACEMODE_FORCE);
681 bool interlaceMethodPresent = GetInteger(pElement, "interlacemethod", interlaceMethod, VS_INTERLACEMETHOD_AUTO, VS_INTERLACEMETHOD_AUTO, VS_INTERLACEMETHOD_MAX);
682 // For smooth conversion of settings stored before the deinterlaceMode existed
683 if (!deinterlaceModePresent && interlaceMethodPresent)
685 if (interlaceMethod == VS_INTERLACEMETHOD_NONE)
687 deinterlaceMode = VS_DEINTERLACEMODE_OFF;
688 interlaceMethod = VS_INTERLACEMETHOD_AUTO;
690 else if (interlaceMethod == VS_INTERLACEMETHOD_AUTO)
692 deinterlaceMode = VS_DEINTERLACEMODE_AUTO;
696 deinterlaceMode = VS_DEINTERLACEMODE_FORCE;
699 m_defaultVideoSettings.m_DeinterlaceMode = (EDEINTERLACEMODE)deinterlaceMode;
700 m_defaultVideoSettings.m_InterlaceMethod = (EINTERLACEMETHOD)interlaceMethod;
702 GetInteger(pElement, "scalingmethod", scalingMethod, VS_SCALINGMETHOD_LINEAR, VS_SCALINGMETHOD_NEAREST, VS_SCALINGMETHOD_MAX);
703 m_defaultVideoSettings.m_ScalingMethod = (ESCALINGMETHOD)scalingMethod;
705 GetInteger(pElement, "viewmode", m_defaultVideoSettings.m_ViewMode, VIEW_MODE_NORMAL, VIEW_MODE_NORMAL, VIEW_MODE_CUSTOM);
706 GetFloat(pElement, "zoomamount", m_defaultVideoSettings.m_CustomZoomAmount, 1.0f, 0.5f, 2.0f);
707 GetFloat(pElement, "pixelratio", m_defaultVideoSettings.m_CustomPixelRatio, 1.0f, 0.5f, 2.0f);
708 GetFloat(pElement, "verticalshift", m_defaultVideoSettings.m_CustomVerticalShift, 0.0f, -2.0f, 2.0f);
709 GetFloat(pElement, "volumeamplification", m_defaultVideoSettings.m_VolumeAmplification, VOLUME_DRC_MINIMUM * 0.01f, VOLUME_DRC_MINIMUM * 0.01f, VOLUME_DRC_MAXIMUM * 0.01f);
710 GetFloat(pElement, "noisereduction", m_defaultVideoSettings.m_NoiseReduction, 0.0f, 0.0f, 1.0f);
711 XMLUtils::GetBoolean(pElement, "postprocess", m_defaultVideoSettings.m_PostProcess);
712 GetFloat(pElement, "sharpness", m_defaultVideoSettings.m_Sharpness, 0.0f, -1.0f, 1.0f);
713 XMLUtils::GetBoolean(pElement, "outputtoallspeakers", m_defaultVideoSettings.m_OutputToAllSpeakers);
714 XMLUtils::GetBoolean(pElement, "showsubtitles", m_defaultVideoSettings.m_SubtitleOn);
715 GetFloat(pElement, "brightness", m_defaultVideoSettings.m_Brightness, 50, 0, 100);
716 GetFloat(pElement, "contrast", m_defaultVideoSettings.m_Contrast, 50, 0, 100);
717 GetFloat(pElement, "gamma", m_defaultVideoSettings.m_Gamma, 20, 0, 100);
718 GetFloat(pElement, "audiodelay", m_defaultVideoSettings.m_AudioDelay, 0.0f, -10.0f, 10.0f);
719 GetFloat(pElement, "subtitledelay", m_defaultVideoSettings.m_SubtitleDelay, 0.0f, -10.0f, 10.0f);
720 XMLUtils::GetBoolean(pElement, "autocrop", m_defaultVideoSettings.m_Crop);
721 XMLUtils::GetBoolean(pElement, "nonlinstretch", m_defaultVideoSettings.m_CustomNonLinStretch);
723 m_defaultVideoSettings.m_SubtitleCached = false;
726 pElement = pRootElement->FirstChildElement("audio");
729 XMLUtils::GetBoolean(pElement, "mute", m_bMute);
730 GetInteger(pElement, "volumelevel", m_nVolumeLevel, VOLUME_MAXIMUM, VOLUME_MINIMUM, VOLUME_MAXIMUM);
731 GetInteger(pElement, "premutevolumelevel", m_iPreMuteVolumeLevel, 0, 0, 100);
732 GetInteger(pElement, "dynamicrangecompression", m_dynamicRangeCompressionLevel, VOLUME_DRC_MINIMUM, VOLUME_DRC_MINIMUM, VOLUME_DRC_MAXIMUM);
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::Log(LOGNOTICE, "Enabled debug logging due to GUI setting (%d)", g_advancedSettings.m_logLevel);
763 g_advancedSettings.m_logLevel = std::min(g_advancedSettings.m_logLevelHint, LOG_LEVEL_DEBUG/*LOG_LEVEL_NORMAL*/);
764 CLog::Log(LOGNOTICE, "Disabled debug logging due to GUI setting. Level %d.", g_advancedSettings.m_logLevel);
766 CLog::SetLogLevel(g_advancedSettings.m_logLevel);
770 bool CSettings::LoadPlayerCoreFactorySettings(const CStdString& fileStr, bool clear)
772 CLog::Log(LOGNOTICE, "Loading player core factory settings from %s.", fileStr.c_str());
773 if (!CFile::Exists(fileStr))
774 { // tell the user it doesn't exist
775 CLog::Log(LOGNOTICE, "%s does not exist. Skipping.", fileStr.c_str());
779 TiXmlDocument playerCoreFactoryXML;
780 if (!playerCoreFactoryXML.LoadFile(fileStr))
782 CLog::Log(LOGERROR, "Error loading %s, Line %d (%s)", fileStr.c_str(), playerCoreFactoryXML.ErrorRow(), playerCoreFactoryXML.ErrorDesc());
786 return CPlayerCoreFactory::LoadConfiguration(playerCoreFactoryXML.RootElement(), clear);
789 bool CSettings::SaveSettings(const CStdString& strSettingsFile, CGUISettings *localSettings /* = NULL */) const
791 TiXmlDocument xmlDoc;
792 TiXmlElement xmlRootElement("settings");
793 TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
794 if (!pRoot) return false;
795 // write our tags one by one - just a big list for now (can be flashed up later)
798 TiXmlElement musicNode("mymusic");
799 TiXmlNode *pNode = pRoot->InsertEndChild(musicNode);
800 if (!pNode) return false;
802 TiXmlElement childNode("playlist");
803 TiXmlNode *pChild = pNode->InsertEndChild(childNode);
804 if (!pChild) return false;
805 XMLUtils::SetBoolean(pChild, "repeat", m_bMyMusicPlaylistRepeat);
806 XMLUtils::SetBoolean(pChild, "shuffle", m_bMyMusicPlaylistShuffle);
809 TiXmlElement childNode("scanning");
810 TiXmlNode *pChild = pNode->InsertEndChild(childNode);
811 if (!pChild) return false;
812 XMLUtils::SetBoolean(pChild, "isscanning", m_bMyMusicIsScanning);
815 XMLUtils::SetInt(pNode, "startwindow", m_iMyMusicStartWindow);
816 XMLUtils::SetBoolean(pNode, "songinfoinvis", m_bMyMusicSongInfoInVis);
817 XMLUtils::SetBoolean(pNode, "songthumbinvis", m_bMyMusicSongThumbInVis);
818 XMLUtils::SetPath(pNode, "defaultlibview", m_defaultMusicLibSource);
821 TiXmlElement videosNode("myvideos");
822 pNode = pRoot->InsertEndChild(videosNode);
823 if (!pNode) return false;
825 XMLUtils::SetInt(pNode, "startwindow", m_iVideoStartWindow);
827 XMLUtils::SetBoolean(pNode, "stackvideos", m_videoStacking);
829 XMLUtils::SetInt(pNode, "watchmodemovies", m_watchMode.find("movies")->second);
830 XMLUtils::SetInt(pNode, "watchmodetvshows", m_watchMode.find("tvshows")->second);
831 XMLUtils::SetInt(pNode, "watchmodemusicvideos", m_watchMode.find("musicvideos")->second);
833 XMLUtils::SetBoolean(pNode, "flatten", m_bMyVideoNavFlatten);
836 TiXmlElement childNode("playlist");
837 TiXmlNode *pChild = pNode->InsertEndChild(childNode);
838 if (!pChild) return false;
839 XMLUtils::SetBoolean(pChild, "repeat", m_bMyVideoPlaylistRepeat);
840 XMLUtils::SetBoolean(pChild, "shuffle", m_bMyVideoPlaylistShuffle);
844 TiXmlElement viewStateNode("viewstates");
845 pNode = pRoot->InsertEndChild(viewStateNode);
848 SetViewState(pNode, "musicnavartists", m_viewStateMusicNavArtists);
849 SetViewState(pNode, "musicnavalbums", m_viewStateMusicNavAlbums);
850 SetViewState(pNode, "musicnavsongs", m_viewStateMusicNavSongs);
851 SetViewState(pNode, "musiclastfm", m_viewStateMusicLastFM);
852 SetViewState(pNode, "videonavactors", m_viewStateVideoNavActors);
853 SetViewState(pNode, "videonavyears", m_viewStateVideoNavYears);
854 SetViewState(pNode, "videonavgenres", m_viewStateVideoNavGenres);
855 SetViewState(pNode, "videonavtitles", m_viewStateVideoNavTitles);
856 SetViewState(pNode, "videonavepisodes", m_viewStateVideoNavEpisodes);
857 SetViewState(pNode, "videonavseasons", m_viewStateVideoNavSeasons);
858 SetViewState(pNode, "videonavtvshows", m_viewStateVideoNavTvShows);
859 SetViewState(pNode, "videonavmusicvideos", m_viewStateVideoNavMusicVideos);
861 SetViewState(pNode, "programs", m_viewStatePrograms);
862 SetViewState(pNode, "pictures", m_viewStatePictures);
863 SetViewState(pNode, "videofiles", m_viewStateVideoFiles);
864 SetViewState(pNode, "musicfiles", m_viewStateMusicFiles);
868 TiXmlElement generalNode("general");
869 pNode = pRoot->InsertEndChild(generalNode);
870 if (!pNode) return false;
871 XMLUtils::SetInt(pNode, "systemtotaluptime", m_iSystemTimeTotalUp);
872 XMLUtils::SetInt(pNode, "httpapibroadcastport", m_HttpApiBroadcastPort);
873 XMLUtils::SetInt(pNode, "httpapibroadcastlevel", m_HttpApiBroadcastLevel);
874 XMLUtils::SetBoolean(pNode, "addonautoupdate", m_bAddonAutoUpdate);
875 XMLUtils::SetBoolean(pNode, "addonnotifications", m_bAddonNotifications);
877 // default video settings
878 TiXmlElement videoSettingsNode("defaultvideosettings");
879 pNode = pRoot->InsertEndChild(videoSettingsNode);
880 if (!pNode) return false;
881 XMLUtils::SetInt(pNode, "deinterlacemode", m_defaultVideoSettings.m_DeinterlaceMode);
882 XMLUtils::SetInt(pNode, "interlacemethod", m_defaultVideoSettings.m_InterlaceMethod);
883 XMLUtils::SetInt(pNode, "scalingmethod", m_defaultVideoSettings.m_ScalingMethod);
884 XMLUtils::SetFloat(pNode, "noisereduction", m_defaultVideoSettings.m_NoiseReduction);
885 XMLUtils::SetBoolean(pNode, "postprocess", m_defaultVideoSettings.m_PostProcess);
886 XMLUtils::SetFloat(pNode, "sharpness", m_defaultVideoSettings.m_Sharpness);
887 XMLUtils::SetInt(pNode, "viewmode", m_defaultVideoSettings.m_ViewMode);
888 XMLUtils::SetFloat(pNode, "zoomamount", m_defaultVideoSettings.m_CustomZoomAmount);
889 XMLUtils::SetFloat(pNode, "pixelratio", m_defaultVideoSettings.m_CustomPixelRatio);
890 XMLUtils::SetFloat(pNode, "verticalshift", m_defaultVideoSettings.m_CustomVerticalShift);
891 XMLUtils::SetFloat(pNode, "volumeamplification", m_defaultVideoSettings.m_VolumeAmplification);
892 XMLUtils::SetBoolean(pNode, "outputtoallspeakers", m_defaultVideoSettings.m_OutputToAllSpeakers);
893 XMLUtils::SetBoolean(pNode, "showsubtitles", m_defaultVideoSettings.m_SubtitleOn);
894 XMLUtils::SetFloat(pNode, "brightness", m_defaultVideoSettings.m_Brightness);
895 XMLUtils::SetFloat(pNode, "contrast", m_defaultVideoSettings.m_Contrast);
896 XMLUtils::SetFloat(pNode, "gamma", m_defaultVideoSettings.m_Gamma);
897 XMLUtils::SetFloat(pNode, "audiodelay", m_defaultVideoSettings.m_AudioDelay);
898 XMLUtils::SetFloat(pNode, "subtitledelay", m_defaultVideoSettings.m_SubtitleDelay);
899 XMLUtils::SetBoolean(pNode, "autocrop", m_defaultVideoSettings.m_Crop);
900 XMLUtils::SetBoolean(pNode, "nonlinstretch", m_defaultVideoSettings.m_CustomNonLinStretch);
904 TiXmlElement volumeNode("audio");
905 pNode = pRoot->InsertEndChild(volumeNode);
906 if (!pNode) return false;
907 XMLUtils::SetBoolean(pNode, "mute", m_bMute);
908 XMLUtils::SetInt(pNode, "volumelevel", m_nVolumeLevel);
909 XMLUtils::SetInt(pNode, "premutevolumelevel", m_iPreMuteVolumeLevel);
910 XMLUtils::SetInt(pNode, "dynamicrangecompression", m_dynamicRangeCompressionLevel);
912 SaveCalibration(pRoot);
914 if (localSettings) // local settings to save
915 localSettings->SaveXML(pRoot);
916 else // save the global settings
917 g_guiSettings.SaveXML(pRoot);
919 SaveSkinSettings(pRoot);
922 SaveProfiles( PROFILES_FILE );
925 return xmlDoc.SaveFile(strSettingsFile);
928 bool CSettings::LoadProfile(unsigned int index)
930 unsigned int oldProfile = m_currentProfile;
931 m_currentProfile = index;
932 CStdString strOldSkin = g_guiSettings.GetString("lookandfeel.skin");
933 CStdString strOldFont = g_guiSettings.GetString("lookandfeel.font");
934 CStdString strOldTheme = g_guiSettings.GetString("lookandfeel.skintheme");
935 CStdString strOldColors = g_guiSettings.GetString("lookandfeel.skincolors");
938 CreateProfileFolders();
940 // initialize our charset converter
941 g_charsetConverter.reset();
943 // Load the langinfo to have user charset <-> utf-8 conversion
944 CStdString strLanguage = g_guiSettings.GetString("locale.language");
945 strLanguage[0] = toupper(strLanguage[0]);
947 CStdString strLangInfoPath;
948 strLangInfoPath.Format("special://xbmc/language/%s/langinfo.xml", strLanguage.c_str());
949 CLog::Log(LOGINFO, "load language info file:%s", strLangInfoPath.c_str());
950 g_langInfo.Load(strLangInfoPath);
952 CStdString strLanguagePath;
953 strLanguagePath.Format("special://xbmc/language/%s/strings.xml", strLanguage.c_str());
955 CButtonTranslator::GetInstance().Load();
956 g_localizeStrings.Load(strLanguagePath);
958 g_Mouse.SetEnabled(g_guiSettings.GetBool("input.enablemouse"));
960 g_infoManager.ResetCache();
961 g_infoManager.ResetLibraryBools();
963 // always reload the skin - we need it for the new language strings
964 g_application.ReloadSkin();
966 if (m_currentProfile != 0)
969 if (doc.LoadFile(URIUtils::AddFileToFolder(GetUserDataFolder(),"guisettings.xml")))
970 g_guiSettings.LoadMasterLock(doc.RootElement());
973 CPasswordManager::GetInstance().Clear();
975 // to set labels - shares are reloaded
976 #if !defined(_WIN32) && defined(HAS_DVD_DRIVE)
977 MEDIA_DETECT::CDetectDVDMedia::UpdateState();
980 CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_WINDOW_RESET);
981 g_windowManager.SendMessage(msg);
983 CUtil::DeleteMusicDatabaseDirectoryCache();
984 CUtil::DeleteVideoDatabaseDirectoryCache();
986 ADDON::CAddonMgr::Get().StartServices(false);
991 m_currentProfile = oldProfile;
996 bool CSettings::DeleteProfile(unsigned int index)
998 const CProfile *profile = GetProfile(index);
1002 CGUIDialogYesNo* dlgYesNo = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
1006 CStdString str = g_localizeStrings.Get(13201);
1007 message.Format(str.c_str(), profile->getName());
1008 dlgYesNo->SetHeading(13200);
1009 dlgYesNo->SetLine(0, message);
1010 dlgYesNo->SetLine(1, "");
1011 dlgYesNo->SetLine(2, "");
1012 dlgYesNo->DoModal();
1014 if (dlgYesNo->IsConfirmed())
1017 CStdString strDirectory = profile->getDirectory();
1018 m_vecProfiles.erase(m_vecProfiles.begin()+index);
1019 if (index == m_currentProfile)
1025 CFileItemPtr item = CFileItemPtr(new CFileItem(URIUtils::AddFileToFolder(GetUserDataFolder(), strDirectory)));
1026 item->SetPath(URIUtils::AddFileToFolder(GetUserDataFolder(), strDirectory + "/"));
1027 item->m_bIsFolder = true;
1029 CFileUtils::DeleteItem(item);
1035 SaveProfiles( PROFILES_FILE );
1040 void CSettings::LoadProfiles(const CStdString& profilesFile)
1042 // clear out our profiles
1043 m_vecProfiles.clear();
1045 TiXmlDocument profilesDoc;
1046 if (CFile::Exists(profilesFile))
1048 if (profilesDoc.LoadFile(profilesFile))
1050 TiXmlElement *rootElement = profilesDoc.RootElement();
1051 if (rootElement && strcmpi(rootElement->Value(),"profiles") == 0)
1053 XMLUtils::GetUInt(rootElement, "lastloaded", m_lastUsedProfile);
1054 XMLUtils::GetBoolean(rootElement, "useloginscreen", m_usingLoginScreen);
1055 XMLUtils::GetInt(rootElement, "nextIdProfile", m_nextIdProfile);
1057 TiXmlElement* pProfile = rootElement->FirstChildElement("profile");
1059 CStdString defaultDir("special://home/userdata");
1060 if (!CDirectory::Exists(defaultDir))
1061 defaultDir = "special://xbmc/userdata";
1064 CProfile profile(defaultDir);
1065 profile.Load(pProfile,GetNextProfileId());
1066 AddProfile(profile);
1067 pProfile = pProfile->NextSiblingElement("profile");
1071 CLog::Log(LOGERROR, "Error loading %s, no <profiles> node", profilesFile.c_str());
1074 CLog::Log(LOGERROR, "Error loading %s, Line %d\n%s", profilesFile.c_str(), profilesDoc.ErrorRow(), profilesDoc.ErrorDesc());
1077 if (m_vecProfiles.empty())
1078 { // add the master user
1079 CProfile profile("special://masterprofile/", "Master user",0);
1080 AddProfile(profile);
1083 // check the validity of the previous profile index
1084 if (m_lastUsedProfile >= m_vecProfiles.size())
1085 m_lastUsedProfile = 0;
1087 m_currentProfile = m_lastUsedProfile;
1089 // the login screen runs as the master profile, so if we're using this, we need to ensure
1090 // we switch to the master profile
1091 if (m_usingLoginScreen)
1092 m_currentProfile = 0;
1095 bool CSettings::SaveProfiles(const CStdString& profilesFile) const
1097 TiXmlDocument xmlDoc;
1098 TiXmlElement xmlRootElement("profiles");
1099 TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
1100 if (!pRoot) return false;
1101 XMLUtils::SetInt(pRoot,"lastloaded", m_currentProfile);
1102 XMLUtils::SetBoolean(pRoot,"useloginscreen",m_usingLoginScreen);
1103 XMLUtils::SetInt(pRoot,"nextIdProfile",m_nextIdProfile);
1104 for (unsigned int i = 0; i < m_vecProfiles.size(); ++i)
1105 m_vecProfiles[i].Save(pRoot);
1108 return xmlDoc.SaveFile(profilesFile);
1111 bool CSettings::LoadUPnPXml(const CStdString& strSettingsFile)
1113 TiXmlDocument UPnPDoc;
1115 if (!CFile::Exists(strSettingsFile))
1116 { // set defaults, or assume no rss feeds??
1119 if (!UPnPDoc.LoadFile(strSettingsFile))
1121 CLog::Log(LOGERROR, "Error loading %s, Line %d\n%s", strSettingsFile.c_str(), UPnPDoc.ErrorRow(), UPnPDoc.ErrorDesc());
1125 TiXmlElement *pRootElement = UPnPDoc.RootElement();
1126 if (!pRootElement || strcmpi(pRootElement->Value(),"upnpserver") != 0)
1128 CLog::Log(LOGERROR, "Error loading %s, no <upnpserver> node", strSettingsFile.c_str());
1133 // default values for ports
1134 m_UPnPPortServer = 0;
1135 m_UPnPPortRenderer = 0;
1136 m_UPnPMaxReturnedItems = 0;
1138 XMLUtils::GetString(pRootElement, "UUID", m_UPnPUUIDServer);
1139 XMLUtils::GetInt(pRootElement, "Port", m_UPnPPortServer);
1140 XMLUtils::GetInt(pRootElement, "MaxReturnedItems", m_UPnPMaxReturnedItems);
1141 XMLUtils::GetString(pRootElement, "UUIDRenderer", m_UPnPUUIDRenderer);
1142 XMLUtils::GetInt(pRootElement, "PortRenderer", m_UPnPPortRenderer);
1147 bool CSettings::SaveUPnPXml(const CStdString& strSettingsFile) const
1149 TiXmlDocument xmlDoc;
1150 TiXmlElement xmlRootElement("upnpserver");
1151 TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
1152 if (!pRoot) return false;
1154 // create a new Element for UUID
1155 XMLUtils::SetString(pRoot, "UUID", m_UPnPUUIDServer);
1156 XMLUtils::SetInt(pRoot, "Port", m_UPnPPortServer);
1157 XMLUtils::SetInt(pRoot, "MaxReturnedItems", m_UPnPMaxReturnedItems);
1158 XMLUtils::SetString(pRoot, "UUIDRenderer", m_UPnPUUIDRenderer);
1159 XMLUtils::SetInt(pRoot, "PortRenderer", m_UPnPPortRenderer);
1162 return xmlDoc.SaveFile(strSettingsFile);
1165 bool CSettings::UpdateShare(const CStdString &type, const CStdString oldName, const CMediaSource &share)
1167 VECSOURCES *pShares = GetSourcesFromType(type);
1169 if (!pShares) return false;
1171 // update our current share list
1172 CMediaSource* pShare=NULL;
1173 for (IVECSOURCES it = pShares->begin(); it != pShares->end(); it++)
1175 if ((*it).strName == oldName)
1177 (*it).strName = share.strName;
1178 (*it).strPath = share.strPath;
1179 (*it).vecPaths = share.vecPaths;
1188 // Update our XML file as well
1189 return SaveSources();
1192 // NOTE: This function does NOT save the sources.xml file - you need to call SaveSources() separately.
1193 bool CSettings::UpdateSource(const CStdString &strType, const CStdString strOldName, const CStdString &strUpdateElement, const CStdString &strUpdateText)
1195 VECSOURCES *pShares = GetSourcesFromType(strType);
1197 if (!pShares) return false;
1199 for (IVECSOURCES it = pShares->begin(); it != pShares->end(); it++)
1201 if ((*it).strName == strOldName)
1203 if ("name" == strUpdateElement)
1204 (*it).strName = strUpdateText;
1205 else if ("lockmode" == strUpdateElement)
1206 (*it).m_iLockMode = LockType(atoi(strUpdateText));
1207 else if ("lockcode" == strUpdateElement)
1208 (*it).m_strLockCode = strUpdateText;
1209 else if ("badpwdcount" == strUpdateElement)
1210 (*it).m_iBadPwdCount = atoi(strUpdateText);
1211 else if ("thumbnail" == strUpdateElement)
1212 (*it).m_strThumbnailImage = strUpdateText;
1213 else if ("path" == strUpdateElement)
1215 (*it).vecPaths.clear();
1216 (*it).strPath = strUpdateText;
1217 (*it).vecPaths.push_back(strUpdateText);
1227 bool CSettings::DeleteSource(const CStdString &strType, const CStdString strName, const CStdString strPath, bool virtualSource)
1229 VECSOURCES *pShares = GetSourcesFromType(strType);
1230 if (!pShares) return false;
1234 for (IVECSOURCES it = pShares->begin(); it != pShares->end(); it++)
1236 if ((*it).strName == strName && (*it).strPath == strPath)
1238 CLog::Log(LOGDEBUG,"found share, removing!");
1248 return SaveSources();
1251 bool CSettings::AddShare(const CStdString &type, const CMediaSource &share)
1253 VECSOURCES *pShares = GetSourcesFromType(type);
1254 if (!pShares) return false;
1256 // translate dir and add to our current shares
1257 CStdString strPath1 = share.strPath;
1259 if(strPath1.IsEmpty())
1261 CLog::Log(LOGERROR, "unable to add empty path");
1265 CMediaSource shareToAdd = share;
1266 if (strPath1.at(0) == '$')
1268 shareToAdd.strPath = CUtil::TranslateSpecialSource(strPath1);
1269 if (!share.strPath.IsEmpty())
1270 CLog::Log(LOGDEBUG, "%s Translated (%s) to Path (%s)",__FUNCTION__ ,strPath1.c_str(),shareToAdd.strPath.c_str());
1273 CLog::Log(LOGDEBUG, "%s Skipping invalid special directory token: %s",__FUNCTION__,strPath1.c_str());
1277 pShares->push_back(shareToAdd);
1279 if (!share.m_ignore)
1281 return SaveSources();
1286 bool CSettings::SaveSources()
1288 // TODO: Should we be specifying utf8 here??
1290 TiXmlElement xmlRootElement("sources");
1291 TiXmlNode *pRoot = doc.InsertEndChild(xmlRootElement);
1292 if (!pRoot) return false;
1294 // ok, now run through and save each sources section
1295 SetSources(pRoot, "programs", m_programSources, m_defaultProgramSource);
1296 SetSources(pRoot, "video", m_videoSources, "");
1297 SetSources(pRoot, "music", m_musicSources, m_defaultMusicSource);
1298 SetSources(pRoot, "pictures", m_pictureSources, m_defaultPictureSource);
1299 SetSources(pRoot, "files", m_fileSources, m_defaultFileSource);
1301 return doc.SaveFile(GetSourcesFile());
1304 bool CSettings::SetSources(TiXmlNode *root, const char *section, const VECSOURCES &shares, const char *defaultPath)
1306 TiXmlElement sectionElement(section);
1307 TiXmlNode *sectionNode = root->InsertEndChild(sectionElement);
1310 XMLUtils::SetPath(sectionNode, "default", defaultPath);
1311 for (unsigned int i = 0; i < shares.size(); i++)
1313 const CMediaSource &share = shares[i];
1316 TiXmlElement source("source");
1318 XMLUtils::SetString(&source, "name", share.strName);
1320 for (unsigned int i = 0; i < share.vecPaths.size(); i++)
1321 XMLUtils::SetPath(&source, "path", share.vecPaths[i]);
1323 if (share.m_iHasLock)
1325 XMLUtils::SetInt(&source, "lockmode", share.m_iLockMode);
1326 XMLUtils::SetString(&source, "lockcode", share.m_strLockCode);
1327 XMLUtils::SetInt(&source, "badpwdcount", share.m_iBadPwdCount);
1329 if (!share.m_strThumbnailImage.IsEmpty())
1330 XMLUtils::SetPath(&source, "thumbnail", share.m_strThumbnailImage);
1332 sectionNode->InsertEndChild(source);
1338 void CSettings::LoadSources()
1341 m_fileSources.clear();
1342 m_musicSources.clear();
1343 m_pictureSources.clear();
1344 m_programSources.clear();
1345 m_videoSources.clear();
1347 CStdString strSourcesFile = GetSourcesFile();
1348 CLog::Log(LOGNOTICE, "Loading media sources from %s", strSourcesFile.c_str());
1351 TiXmlDocument xmlDoc;
1352 TiXmlElement *pRootElement = NULL;
1353 if (xmlDoc.LoadFile(strSourcesFile))
1355 pRootElement = xmlDoc.RootElement();
1356 if (pRootElement && strcmpi(pRootElement->Value(),"sources") != 0)
1357 CLog::Log(LOGERROR, "%s sources.xml file does not contain <sources>", __FUNCTION__);
1359 else if (CFile::Exists(strSourcesFile))
1360 CLog::Log(LOGERROR, "%s Error loading %s: Line %d, %s", __FUNCTION__, strSourcesFile.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
1366 GetSources(pRootElement, "programs", m_programSources, m_defaultProgramSource);
1367 GetSources(pRootElement, "pictures", m_pictureSources, m_defaultPictureSource);
1368 GetSources(pRootElement, "files", m_fileSources, m_defaultFileSource);
1369 GetSources(pRootElement, "music", m_musicSources, m_defaultMusicSource);
1370 GetSources(pRootElement, "video", m_videoSources, dummy);
1374 void CSettings::LoadSkinSettings(const TiXmlElement* pRootElement)
1377 const TiXmlElement *pElement = pRootElement->FirstChildElement("skinsettings");
1380 m_skinStrings.clear();
1381 m_skinBools.clear();
1382 const TiXmlElement *pChild = pElement->FirstChildElement("setting");
1385 CStdString settingName = pChild->Attribute("name");
1386 if (pChild->Attribute("type") && strcmpi(pChild->Attribute("type"),"string") == 0)
1389 string.name = settingName;
1390 string.value = pChild->FirstChild() ? pChild->FirstChild()->Value() : "";
1391 m_skinStrings.insert(pair<int, CSkinString>(number++, string));
1396 setting.name = settingName;
1397 setting.value = pChild->FirstChild() ? strcmpi(pChild->FirstChild()->Value(), "true") == 0 : false;
1398 m_skinBools.insert(pair<int, CSkinBool>(number++, setting));
1400 pChild = pChild->NextSiblingElement("setting");
1405 void CSettings::SaveSkinSettings(TiXmlNode *pRootElement) const
1407 // add the <skinsettings> tag
1408 TiXmlElement xmlSettingsElement("skinsettings");
1409 TiXmlNode *pSettingsNode = pRootElement->InsertEndChild(xmlSettingsElement);
1410 if (!pSettingsNode) return;
1411 for (map<int, CSkinBool>::const_iterator it = m_skinBools.begin(); it != m_skinBools.end(); ++it)
1413 // Add a <setting type="bool" name="name">true/false</setting>
1414 TiXmlElement xmlSetting("setting");
1415 xmlSetting.SetAttribute("type", "bool");
1416 xmlSetting.SetAttribute("name", (*it).second.name.c_str());
1417 TiXmlText xmlBool((*it).second.value ? "true" : "false");
1418 xmlSetting.InsertEndChild(xmlBool);
1419 pSettingsNode->InsertEndChild(xmlSetting);
1421 for (map<int, CSkinString>::const_iterator it = m_skinStrings.begin(); it != m_skinStrings.end(); ++it)
1423 // Add a <setting type="string" name="name">string</setting>
1424 TiXmlElement xmlSetting("setting");
1425 xmlSetting.SetAttribute("type", "string");
1426 xmlSetting.SetAttribute("name", (*it).second.name.c_str());
1427 TiXmlText xmlLabel((*it).second.value);
1428 xmlSetting.InsertEndChild(xmlLabel);
1429 pSettingsNode->InsertEndChild(xmlSetting);
1433 void CSettings::Clear()
1435 m_programSources.clear();
1436 m_pictureSources.clear();
1437 m_fileSources.clear();
1438 m_musicSources.clear();
1439 m_videoSources.clear();
1440 // m_vecIcons.clear();
1441 m_vecProfiles.clear();
1442 m_mapRssUrls.clear();
1443 m_skinBools.clear();
1444 m_skinStrings.clear();
1447 int CSettings::TranslateSkinString(const CStdString &setting)
1449 CStdString settingName;
1450 settingName.Format("%s.%s", g_guiSettings.GetString("lookandfeel.skin").c_str(), setting);
1451 // run through and see if we have this setting
1452 for (map<int, CSkinString>::const_iterator it = m_skinStrings.begin(); it != m_skinStrings.end(); it++)
1454 if (settingName.Equals((*it).second.name))
1457 // didn't find it - insert it
1458 CSkinString skinString;
1459 skinString.name = settingName;
1460 m_skinStrings.insert(pair<int, CSkinString>(m_skinStrings.size() + m_skinBools.size(), skinString));
1461 return m_skinStrings.size() + m_skinBools.size() - 1;
1464 const CStdString &CSettings::GetSkinString(int setting) const
1466 map<int, CSkinString>::const_iterator it = m_skinStrings.find(setting);
1467 if (it != m_skinStrings.end())
1469 return (*it).second.value;
1471 return StringUtils::EmptyString;
1474 void CSettings::SetSkinString(int setting, const CStdString &label)
1476 map<int, CSkinString>::iterator it = m_skinStrings.find(setting);
1477 if (it != m_skinStrings.end())
1479 (*it).second.value = label;
1483 CLog::Log(LOGFATAL, "%s : Unknown setting requested", __FUNCTION__);
1486 void CSettings::ResetSkinSetting(const CStdString &setting)
1488 CStdString settingName;
1489 settingName.Format("%s.%s", g_guiSettings.GetString("lookandfeel.skin").c_str(), setting);
1490 // run through and see if we have this setting as a string
1491 for (map<int, CSkinString>::iterator it = m_skinStrings.begin(); it != m_skinStrings.end(); it++)
1493 if (settingName.Equals((*it).second.name))
1495 (*it).second.value = "";
1499 // and now check for the skin bool
1500 for (map<int, CSkinBool>::iterator it = m_skinBools.begin(); it != m_skinBools.end(); it++)
1502 if (settingName.Equals((*it).second.name))
1504 (*it).second.value = false;
1510 int CSettings::TranslateSkinBool(const CStdString &setting)
1512 CStdString settingName;
1513 settingName.Format("%s.%s", g_guiSettings.GetString("lookandfeel.skin").c_str(), setting);
1514 // run through and see if we have this setting
1515 for (map<int, CSkinBool>::const_iterator it = m_skinBools.begin(); it != m_skinBools.end(); it++)
1517 if (settingName.Equals((*it).second.name))
1520 // didn't find it - insert it
1522 skinBool.name = settingName;
1523 skinBool.value = false;
1524 m_skinBools.insert(pair<int, CSkinBool>(m_skinBools.size() + m_skinStrings.size(), skinBool));
1525 return m_skinBools.size() + m_skinStrings.size() - 1;
1528 bool CSettings::GetSkinBool(int setting) const
1530 map<int, CSkinBool>::const_iterator it = m_skinBools.find(setting);
1531 if (it != m_skinBools.end())
1533 return (*it).second.value;
1535 // default is to return false
1539 void CSettings::SetSkinBool(int setting, bool set)
1541 map<int, CSkinBool>::iterator it = m_skinBools.find(setting);
1542 if (it != m_skinBools.end())
1544 (*it).second.value = set;
1548 CLog::Log(LOGFATAL,"%s : Unknown setting requested", __FUNCTION__);
1551 void CSettings::ResetSkinSettings()
1553 CStdString currentSkin = g_guiSettings.GetString("lookandfeel.skin") + ".";
1554 // clear all the settings and strings from this skin.
1555 map<int, CSkinBool>::iterator it = m_skinBools.begin();
1556 while (it != m_skinBools.end())
1558 CStdString skinName = (*it).second.name;
1559 if (skinName.Left(currentSkin.size()) == currentSkin)
1560 (*it).second.value = false;
1564 map<int, CSkinString>::iterator it2 = m_skinStrings.begin();
1565 while (it2 != m_skinStrings.end())
1567 CStdString skinName = (*it2).second.name;
1568 if (skinName.Left(currentSkin.size()) == currentSkin)
1569 (*it2).second.value = "";
1573 g_infoManager.ResetCache();
1576 static CStdString ToWatchContent(const CStdString &content)
1578 if (content == "seasons" || content == "episodes")
1584 int CSettings::GetWatchMode(const CStdString& content) const
1586 std::map<CStdString, int>::iterator it = g_settings.m_watchMode.find(ToWatchContent(content));
1587 if (it != g_settings.m_watchMode.end())
1589 return VIDEO_SHOW_ALL;
1592 void CSettings::SetWatchMode(const CStdString& content, int value)
1594 std::map<CStdString, int>::iterator it = g_settings.m_watchMode.find(ToWatchContent(content));
1595 if (it != g_settings.m_watchMode.end())
1599 void CSettings::CycleWatchMode(const CStdString& content)
1601 std::map<CStdString, int>::iterator it = g_settings.m_watchMode.find(ToWatchContent(content));
1602 if (it != g_settings.m_watchMode.end())
1605 if (it->second > VIDEO_SHOW_WATCHED)
1606 it->second = VIDEO_SHOW_ALL;
1610 void CSettings::LoadUserFolderLayout()
1613 CStdString strDir = g_guiSettings.GetString("system.playlistspath");
1614 if (strDir == "set default")
1616 strDir = "special://profile/playlists/";
1617 g_guiSettings.SetString("system.playlistspath",strDir.c_str());
1619 CDirectory::Create(strDir);
1620 CDirectory::Create(URIUtils::AddFileToFolder(strDir,"music"));
1621 CDirectory::Create(URIUtils::AddFileToFolder(strDir,"video"));
1622 CDirectory::Create(URIUtils::AddFileToFolder(strDir,"mixed"));
1625 CStdString CSettings::GetProfileUserDataFolder() const
1628 if (m_currentProfile == 0)
1629 return GetUserDataFolder();
1631 URIUtils::AddFileToFolder(GetUserDataFolder(),GetCurrentProfile().getDirectory(),folder);
1636 CStdString CSettings::GetUserDataItem(const CStdString& strFile) const
1639 folder = "special://profile/"+strFile;
1640 //check if item exists in the profile
1641 //(either for folder or for a file (depending on slashAtEnd of strFile)
1642 //otherwise return path to masterprofile
1643 if ( (URIUtils::HasSlashAtEnd(folder) && !CDirectory::Exists(folder)) || !CFile::Exists(folder))
1644 folder = "special://masterprofile/"+strFile;
1648 CStdString CSettings::GetUserDataFolder() const
1650 return GetMasterProfile().getDirectory();
1653 CStdString CSettings::GetDatabaseFolder() const
1656 if (GetCurrentProfile().hasDatabases())
1657 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Database", folder);
1659 URIUtils::AddFileToFolder(GetUserDataFolder(), "Database", folder);
1664 CStdString CSettings::GetCDDBFolder() const
1667 if (GetCurrentProfile().hasDatabases())
1668 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Database/CDDB", folder);
1670 URIUtils::AddFileToFolder(GetUserDataFolder(), "Database/CDDB", folder);
1675 CStdString CSettings::GetThumbnailsFolder() const
1678 if (GetCurrentProfile().hasDatabases())
1679 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails", folder);
1681 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails", folder);
1686 CStdString CSettings::GetMusicThumbFolder() const
1689 if (GetCurrentProfile().hasDatabases())
1690 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music", folder);
1692 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music", folder);
1697 CStdString CSettings::GetLastFMThumbFolder() const
1700 if (GetCurrentProfile().hasDatabases())
1701 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music/LastFM", folder);
1703 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music/LastFM", folder);
1708 CStdString CSettings::GetMusicArtistThumbFolder() const
1711 if (GetCurrentProfile().hasDatabases())
1712 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music/Artists", folder);
1714 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music/Artists", folder);
1719 CStdString CSettings::GetVideoThumbFolder() const
1722 if (GetCurrentProfile().hasDatabases())
1723 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Video", folder);
1725 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Video", folder);
1730 CStdString CSettings::GetVideoFanartFolder() const
1733 if (GetCurrentProfile().hasDatabases())
1734 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Video/Fanart", folder);
1736 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Video/Fanart", folder);
1741 CStdString CSettings::GetMusicFanartFolder() const
1744 if (GetCurrentProfile().hasDatabases())
1745 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Music/Fanart", folder);
1747 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Music/Fanart", folder);
1752 CStdString CSettings::GetBookmarksThumbFolder() const
1755 if (GetCurrentProfile().hasDatabases())
1756 URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails/Video/Bookmarks", folder);
1758 URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails/Video/Bookmarks", folder);
1763 CStdString CSettings::GetSourcesFile() const
1766 if (GetCurrentProfile().hasSources())
1767 URIUtils::AddFileToFolder(GetProfileUserDataFolder(),"sources.xml",folder);
1769 URIUtils::AddFileToFolder(GetUserDataFolder(),"sources.xml",folder);
1774 void CSettings::LoadRSSFeeds()
1777 rssXML = GetUserDataItem("RssFeeds.xml");
1778 TiXmlDocument rssDoc;
1779 if (!CFile::Exists(rssXML))
1780 { // set defaults, or assume no rss feeds??
1783 if (!rssDoc.LoadFile(rssXML))
1785 CLog::Log(LOGERROR, "Error loading %s, Line %d\n%s", rssXML.c_str(), rssDoc.ErrorRow(), rssDoc.ErrorDesc());
1789 TiXmlElement *pRootElement = rssDoc.RootElement();
1790 if (!pRootElement || strcmpi(pRootElement->Value(),"rssfeeds") != 0)
1792 CLog::Log(LOGERROR, "Error loading %s, no <rssfeeds> node", rssXML.c_str());
1796 m_mapRssUrls.clear();
1797 TiXmlElement* pSet = pRootElement->FirstChildElement("set");
1801 if (pSet->QueryIntAttribute("id", &iId) == TIXML_SUCCESS)
1804 set.rtl = pSet->Attribute("rtl") && strcasecmp(pSet->Attribute("rtl"),"true")==0;
1805 TiXmlElement* pFeed = pSet->FirstChildElement("feed");
1809 if ( pFeed->QueryIntAttribute("updateinterval",&iInterval) != TIXML_SUCCESS)
1811 iInterval=30; // default to 30 min
1812 CLog::Log(LOGDEBUG,"no interval set, default to 30!");
1814 if (pFeed->FirstChild())
1816 // TODO: UTF-8: Do these URLs need to be converted to UTF-8?
1817 // What about the xml encoding?
1818 CStdString strUrl = pFeed->FirstChild()->Value();
1819 set.url.push_back(strUrl);
1820 set.interval.push_back(iInterval);
1822 pFeed = pFeed->NextSiblingElement("feed");
1824 m_mapRssUrls.insert(make_pair(iId,set));
1827 CLog::Log(LOGERROR,"found rss url set with no id in RssFeeds.xml, ignored");
1829 pSet = pSet->NextSiblingElement("set");
1833 CStdString CSettings::GetSettingsFile() const
1835 CStdString settings;
1836 if (m_currentProfile == 0)
1837 settings = "special://masterprofile/guisettings.xml";
1839 settings = "special://profile/guisettings.xml";
1843 void CSettings::CreateProfileFolders()
1845 CDirectory::Create(GetDatabaseFolder());
1846 CDirectory::Create(GetCDDBFolder());
1849 CDirectory::Create(GetThumbnailsFolder());
1850 CDirectory::Create(GetMusicThumbFolder());
1851 CDirectory::Create(GetMusicArtistThumbFolder());
1852 CDirectory::Create(GetLastFMThumbFolder());
1853 CDirectory::Create(GetVideoThumbFolder());
1854 CDirectory::Create(GetVideoFanartFolder());
1855 CDirectory::Create(GetMusicFanartFolder());
1856 CDirectory::Create(GetBookmarksThumbFolder());
1857 CStdString generatedThumbsFolder = URIUtils::AddFileToFolder(GetThumbnailsFolder(), "generated");
1858 CDirectory::Create(generatedThumbsFolder);
1859 CLog::Log(LOGINFO, "thumbnails folder: %s", GetThumbnailsFolder().c_str());
1860 for (unsigned int hex=0; hex < 16; hex++)
1863 strHex.Format("%x",hex);
1864 CDirectory::Create(URIUtils::AddFileToFolder(GetMusicThumbFolder(), strHex));
1865 CDirectory::Create(URIUtils::AddFileToFolder(GetVideoThumbFolder(), strHex));
1866 CDirectory::Create(URIUtils::AddFileToFolder(GetThumbnailsFolder(), strHex));
1867 CDirectory::Create(URIUtils::AddFileToFolder(generatedThumbsFolder, strHex));
1869 CDirectory::Create("special://profile/addon_data");
1870 CDirectory::Create("special://profile/keymaps");
1873 static CProfile emptyProfile;
1875 const CProfile &CSettings::GetMasterProfile() const
1877 if (GetNumProfiles())
1878 return m_vecProfiles[0];
1879 CLog::Log(LOGERROR, "%s - master profile requested while none exists", __FUNCTION__);
1880 return emptyProfile;
1883 const CProfile &CSettings::GetCurrentProfile() const
1885 if (m_currentProfile < m_vecProfiles.size())
1886 return m_vecProfiles[m_currentProfile];
1887 CLog::Log(LOGERROR, "%s - last profile index (%u) is outside the valid range (%" PRIdS ")", __FUNCTION__, m_currentProfile, m_vecProfiles.size());
1888 return emptyProfile;
1891 int CSettings::GetCurrentProfileId() const
1893 return GetCurrentProfile().getId();
1896 void CSettings::UpdateCurrentProfileDate()
1898 if (m_currentProfile < m_vecProfiles.size())
1899 m_vecProfiles[m_currentProfile].setDate();
1902 const CProfile *CSettings::GetProfile(unsigned int index) const
1904 if (index < GetNumProfiles())
1905 return &m_vecProfiles[index];
1909 CProfile *CSettings::GetProfile(unsigned int index)
1911 if (index < GetNumProfiles())
1912 return &m_vecProfiles[index];
1916 unsigned int CSettings::GetNumProfiles() const
1918 return m_vecProfiles.size();
1921 int CSettings::GetProfileIndex(const CStdString &name) const
1923 for (unsigned int i = 0; i < m_vecProfiles.size(); i++)
1924 if (m_vecProfiles[i].getName().Equals(name))
1929 void CSettings::AddProfile(const CProfile &profile)
1931 //data integrity check - covers off migration from old profiles.xml, incrementing of the m_nextIdProfile,and bad data coming in
1932 m_nextIdProfile = max(m_nextIdProfile, profile.getId() + 1);
1934 m_vecProfiles.push_back(profile);
1937 void CSettings::LoadMasterForLogin()
1939 // save the previous user
1940 m_lastUsedProfile = m_currentProfile;
1941 if (m_currentProfile != 0)