2 * Copyright (C) 2013-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "ProfileManager.h"
11 #include "ContextMenuManager.h" //! @todo Remove me
12 #include "DatabaseManager.h"
14 #include "GUIInfoManager.h"
15 #include "GUIPassword.h"
16 #include "PasswordManager.h"
17 #include "PlayListPlayer.h" //! @todo Remove me
18 #include "ServiceBroker.h"
20 #include "addons/AddonManager.h" //! @todo Remove me
21 #include "addons/Service.h" //! @todo Remove me
22 #include "addons/Skin.h"
23 #include "application/Application.h" //! @todo Remove me
24 #include "application/ApplicationComponents.h"
25 #include "application/ApplicationPowerHandling.h"
26 #include "dialogs/GUIDialogKaiToast.h"
27 #include "dialogs/GUIDialogYesNo.h"
28 #include "events/EventLog.h"
29 #include "events/EventLogManager.h"
30 #include "favourites/FavouritesService.h" //! @todo Remove me
31 #include "filesystem/Directory.h"
32 #include "filesystem/DirectoryCache.h"
33 #include "filesystem/File.h"
34 #include "filesystem/SpecialProtocol.h"
35 #include "guilib/GUIComponent.h"
36 #include "guilib/GUIWindowManager.h"
37 #include "guilib/LocalizeStrings.h"
38 #include "guilib/StereoscopicsManager.h" //! @todo Remove me
39 #include "input/InputManager.h"
40 #include "interfaces/json-rpc/JSONRPC.h" //! @todo Remove me
41 #include "music/MusicLibraryQueue.h"
42 #include "network/Network.h" //! @todo Remove me
43 #include "network/NetworkServices.h" //! @todo Remove me
44 #include "pvr/PVRManager.h" //! @todo Remove me
45 #include "settings/Settings.h"
46 #include "settings/SettingsComponent.h"
47 #include "settings/lib/SettingsManager.h"
48 #if !defined(TARGET_WINDOWS) && defined(HAS_OPTICAL_DRIVE)
49 #include "storage/DetectDVDType.h"
51 #include "threads/SingleLock.h"
52 #include "utils/FileUtils.h"
53 #include "utils/StringUtils.h"
54 #include "utils/URIUtils.h"
55 #include "utils/Variant.h"
56 #include "utils/XMLUtils.h"
57 #include "utils/log.h"
58 #include "video/VideoLibraryQueue.h" //! @todo Remove me
59 #include "weather/WeatherManager.h" //! @todo Remove me
68 //! eventually the profile should dictate where special://masterprofile/ is
69 //! but for now it makes sense to leave all the profile settings in a user
70 //! writeable location like special://masterprofile/
71 #define PROFILES_FILE "special://masterprofile/profiles.xml"
73 #define XML_PROFILES "profiles"
74 #define XML_AUTO_LOGIN "autologin"
75 #define XML_LAST_LOADED "lastloaded"
76 #define XML_LOGIN_SCREEN "useloginscreen"
77 #define XML_NEXTID "nextIdProfile"
78 #define XML_PROFILE "profile"
81 using namespace XFILE
;
83 static CProfile EmptyProfile
;
85 CProfileManager::CProfileManager() : m_eventLogs(new CEventLogManager
)
89 CProfileManager::~CProfileManager() = default;
91 void CProfileManager::Initialize(const std::shared_ptr
<CSettings
>& settings
)
93 m_settings
= settings
;
95 if (m_settings
->IsLoaded())
98 m_settings
->GetSettingsManager()->RegisterSettingsHandler(this);
100 std::set
<std::string
> settingSet
= {
101 CSettings::SETTING_EVENTLOG_SHOW
104 m_settings
->GetSettingsManager()->RegisterCallback(this, settingSet
);
107 void CProfileManager::Uninitialize()
109 m_settings
->GetSettingsManager()->UnregisterCallback(this);
110 m_settings
->GetSettingsManager()->UnregisterSettingsHandler(this);
113 void CProfileManager::OnSettingsLoaded()
116 std::string strDir
= m_settings
->GetString(CSettings::SETTING_SYSTEM_PLAYLISTSPATH
);
117 if (strDir
== "set default" || strDir
.empty())
119 strDir
= "special://profile/playlists/";
120 m_settings
->SetString(CSettings::SETTING_SYSTEM_PLAYLISTSPATH
, strDir
);
123 CDirectory::Create(strDir
);
124 CDirectory::Create(URIUtils::AddFileToFolder(strDir
,"music"));
125 CDirectory::Create(URIUtils::AddFileToFolder(strDir
,"video"));
126 CDirectory::Create(URIUtils::AddFileToFolder(strDir
,"mixed"));
129 void CProfileManager::OnSettingsSaved() const
135 void CProfileManager::OnSettingsCleared()
140 bool CProfileManager::Load()
143 const std::string file
= PROFILES_FILE
;
145 std::unique_lock
<CCriticalSection
> lock(m_critical
);
147 // clear out our profiles
150 if (CFile::Exists(file
))
152 CXBMCTinyXML profilesDoc
;
153 if (profilesDoc
.LoadFile(file
))
155 const TiXmlElement
*rootElement
= profilesDoc
.RootElement();
156 if (rootElement
&& StringUtils::EqualsNoCase(rootElement
->Value(), XML_PROFILES
))
158 XMLUtils::GetUInt(rootElement
, XML_LAST_LOADED
, m_lastUsedProfile
);
159 XMLUtils::GetBoolean(rootElement
, XML_LOGIN_SCREEN
, m_usingLoginScreen
);
160 XMLUtils::GetInt(rootElement
, XML_AUTO_LOGIN
, m_autoLoginProfile
);
161 XMLUtils::GetInt(rootElement
, XML_NEXTID
, m_nextProfileId
);
163 std::string
defaultDir("special://home/userdata");
164 if (!CDirectory::Exists(defaultDir
))
165 defaultDir
= "special://xbmc/userdata";
167 const TiXmlElement
* pProfile
= rootElement
->FirstChildElement(XML_PROFILE
);
170 CProfile
profile(defaultDir
);
171 profile
.Load(pProfile
, GetNextProfileId());
174 pProfile
= pProfile
->NextSiblingElement(XML_PROFILE
);
179 CLog::Log(LOGERROR
, "CProfileManager: error loading {}, no <profiles> node", file
);
185 CLog::Log(LOGERROR
, "CProfileManager: error loading {}, Line {}\n{}", file
,
186 profilesDoc
.ErrorRow(), profilesDoc
.ErrorDesc());
193 "Failed to load profile - might be corrupted - falling back to master profile");
200 if (m_profiles
.empty())
201 { // add the master user
202 CProfile
profile("special://masterprofile/", "Master user", 0);
206 // check the validity of the previous profile index
207 if (m_lastUsedProfile
>= m_profiles
.size())
208 m_lastUsedProfile
= 0;
210 SetCurrentProfileId(m_lastUsedProfile
);
212 // check the validity of the auto login profile index
213 if (m_autoLoginProfile
< -1 || m_autoLoginProfile
>= (int)m_profiles
.size())
214 m_autoLoginProfile
= -1;
215 else if (m_autoLoginProfile
>= 0)
216 SetCurrentProfileId(m_autoLoginProfile
);
218 // the login screen runs as the master profile, so if we're using this, we need to ensure
219 // we switch to the master profile
220 if (m_usingLoginScreen
)
221 SetCurrentProfileId(0);
226 bool CProfileManager::Save() const
228 const std::string file
= PROFILES_FILE
;
230 std::unique_lock
<CCriticalSection
> lock(m_critical
);
233 TiXmlElement
xmlRootElement(XML_PROFILES
);
234 TiXmlNode
*pRoot
= xmlDoc
.InsertEndChild(xmlRootElement
);
235 if (pRoot
== nullptr)
238 XMLUtils::SetInt(pRoot
, XML_LAST_LOADED
, m_currentProfile
);
239 XMLUtils::SetBoolean(pRoot
, XML_LOGIN_SCREEN
, m_usingLoginScreen
);
240 XMLUtils::SetInt(pRoot
, XML_AUTO_LOGIN
, m_autoLoginProfile
);
241 XMLUtils::SetInt(pRoot
, XML_NEXTID
, m_nextProfileId
);
243 for (const auto& profile
: m_profiles
)
247 return xmlDoc
.SaveFile(file
);
250 void CProfileManager::Clear()
252 std::unique_lock
<CCriticalSection
> lock(m_critical
);
253 m_usingLoginScreen
= false;
254 m_profileLoadedForLogin
= false;
255 m_previousProfileLoadedForLogin
= false;
256 m_lastUsedProfile
= 0;
258 SetCurrentProfileId(0);
262 void CProfileManager::PrepareLoadProfile(unsigned int profileIndex
)
264 CContextMenuManager
&contextMenuManager
= CServiceBroker::GetContextMenuManager();
265 ADDON::CServiceAddonManager
&serviceAddons
= CServiceBroker::GetServiceAddons();
266 PVR::CPVRManager
&pvrManager
= CServiceBroker::GetPVRManager();
267 CNetworkBase
&networkManager
= CServiceBroker::GetNetwork();
269 contextMenuManager
.Deinit();
271 serviceAddons
.Stop();
273 // stop PVR related services
276 if (profileIndex
!= 0 || !IsMasterProfile())
277 networkManager
.NetworkMessage(CNetworkBase::SERVICES_DOWN
, 1);
280 bool CProfileManager::LoadProfile(unsigned int index
)
282 PrepareLoadProfile(index
);
284 if (index
== 0 && IsMasterProfile())
286 CGUIWindow
* pWindow
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow(WINDOW_HOME
);
288 pWindow
->ResetControlStates();
290 UpdateCurrentProfileDate();
291 FinalizeLoadProfile();
296 std::unique_lock
<CCriticalSection
> lock(m_critical
);
297 // check if the index is valid or not
298 if (index
>= m_profiles
.size())
301 // check if the profile is already active
302 if (m_currentProfile
== index
)
305 // save any settings of the currently used skin but only if the (master)
306 // profile hasn't just been loaded as a temporary profile for login
307 if (g_SkinInfo
!= nullptr && !m_previousProfileLoadedForLogin
)
308 g_SkinInfo
->SaveSettings();
310 // @todo: why is m_settings not used here?
311 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
313 // unload any old settings
316 SetCurrentProfileId(index
);
317 m_previousProfileLoadedForLogin
= false;
319 // load the new settings
320 if (!settings
->Load())
322 CLog::Log(LOGFATAL
, "CProfileManager: unable to load settings for profile \"{}\"",
323 m_profiles
.at(index
).getName());
326 settings
->SetLoaded();
328 CreateProfileFolders();
330 CServiceBroker::GetDatabaseManager().Initialize();
331 CServiceBroker::GetInputManager().LoadKeymaps();
333 CServiceBroker::GetInputManager().SetMouseEnabled(settings
->GetBool(CSettings::SETTING_INPUT_ENABLEMOUSE
));
335 CGUIComponent
* gui
= CServiceBroker::GetGUI();
338 CGUIInfoManager
& infoMgr
= gui
->GetInfoManager();
339 infoMgr
.ResetCache();
340 infoMgr
.GetInfoProviders().GetGUIControlsInfoProvider().ResetContainerMovingCache();
341 infoMgr
.GetInfoProviders().GetLibraryInfoProvider().ResetLibraryBools();
344 if (m_currentProfile
!= 0)
347 if (doc
.LoadFile(URIUtils::AddFileToFolder(GetUserDataFolder(), "guisettings.xml")))
349 settings
->LoadSetting(doc
.RootElement(), CSettings::SETTING_MASTERLOCK_MAXRETRIES
);
350 settings
->LoadSetting(doc
.RootElement(), CSettings::SETTING_MASTERLOCK_STARTUPLOCK
);
354 CPasswordManager::GetInstance().Clear();
356 // to set labels - shares are reloaded
357 #if !defined(TARGET_WINDOWS) && defined(HAS_OPTICAL_DRIVE)
358 MEDIA_DETECT::CDetectDVDMedia::UpdateState();
362 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, 0, 0, GUI_MSG_WINDOW_RESET
);
363 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg
);
365 CUtil::DeleteDirectoryCache();
366 g_directoryCache
.Clear();
370 UpdateCurrentProfileDate();
371 FinalizeLoadProfile();
373 m_profileLoadedForLogin
= false;
378 void CProfileManager::FinalizeLoadProfile()
380 CContextMenuManager
&contextMenuManager
= CServiceBroker::GetContextMenuManager();
381 ADDON::CServiceAddonManager
&serviceAddons
= CServiceBroker::GetServiceAddons();
382 PVR::CPVRManager
&pvrManager
= CServiceBroker::GetPVRManager();
383 CNetworkBase
&networkManager
= CServiceBroker::GetNetwork();
384 ADDON::CAddonMgr
&addonManager
= CServiceBroker::GetAddonMgr();
385 CWeatherManager
&weatherManager
= CServiceBroker::GetWeatherManager();
386 CFavouritesService
&favouritesManager
= CServiceBroker::GetFavouritesService();
387 PLAYLIST::CPlayListPlayer
&playlistManager
= CServiceBroker::GetPlaylistPlayer();
388 CStereoscopicsManager
&stereoscopicsManager
= CServiceBroker::GetGUI()->GetStereoscopicsManager();
390 if (m_lastUsedProfile
!= m_currentProfile
)
392 playlistManager
.ClearPlaylist(PLAYLIST::Id::TYPE_VIDEO
);
393 playlistManager
.ClearPlaylist(PLAYLIST::Id::TYPE_MUSIC
);
394 playlistManager
.SetCurrentPlaylist(PLAYLIST::Id::TYPE_NONE
);
397 networkManager
.NetworkMessage(CNetworkBase::SERVICES_UP
, 1);
399 // reload the add-ons, or we will first load all add-ons from the master account without checking disabled status
400 addonManager
.ReInit();
402 // let CApplication know that we are logging into a new profile
403 g_application
.SetLoggingIn(true);
405 if (!g_application
.LoadLanguage(true))
407 CLog::Log(LOGFATAL
, "Unable to load language for profile \"{}\"",
408 GetCurrentProfile().getName());
412 weatherManager
.Refresh();
414 JSONRPC::CJSONRPC::Initialize();
416 // Restart context menu manager
417 contextMenuManager
.Init();
419 // Restart PVR services if we are not just loading the master profile for the login screen
420 if (m_previousProfileLoadedForLogin
|| m_currentProfile
!= 0 || m_lastUsedProfile
== 0)
423 favouritesManager
.ReInit(GetProfileUserDataFolder());
425 // Start these operations only when a profile is loaded, not on the login screen
426 if (!m_profileLoadedForLogin
|| (m_profileLoadedForLogin
&& m_lastUsedProfile
== 0))
428 serviceAddons
.Start();
429 g_application
.UpdateLibraries();
432 stereoscopicsManager
.Initialize();
434 // Load initial window
435 int firstWindow
= g_SkinInfo
->GetFirstWindow();
437 CServiceBroker::GetGUI()->GetWindowManager().ChangeActiveWindow(firstWindow
);
439 //the user interfaces has been fully initialized, let everyone know
440 CGUIMessage
msg(GUI_MSG_NOTIFY_ALL
, WINDOW_SETTINGS_PROFILES
, 0, GUI_MSG_UI_READY
);
441 CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg
);
444 void CProfileManager::LogOff()
446 CNetworkBase
&networkManager
= CServiceBroker::GetNetwork();
448 g_application
.StopPlaying();
450 if (CMusicLibraryQueue::GetInstance().IsScanningLibrary())
451 CMusicLibraryQueue::GetInstance().StopLibraryScanning();
453 if (CVideoLibraryQueue::GetInstance().IsRunning())
454 CVideoLibraryQueue::GetInstance().CancelAllJobs();
457 CServiceBroker::GetPVRManager().Stop();
459 networkManager
.NetworkMessage(CNetworkBase::SERVICES_DOWN
, 1);
461 LoadMasterProfileForLogin();
463 g_passwordManager
.bMasterUser
= false;
465 auto& components
= CServiceBroker::GetAppComponents();
466 const auto appPower
= components
.GetComponent
<CApplicationPowerHandling
>();
467 appPower
->WakeUpScreenSaverAndDPMS();
468 CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_LOGIN_SCREEN
, {}, false);
470 if (!CServiceBroker::GetNetwork().GetServices().StartEventServer()) // event server could be needed in some situations
471 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning
, g_localizeStrings
.Get(33102), g_localizeStrings
.Get(33100));
474 bool CProfileManager::DeleteProfile(unsigned int index
)
476 std::unique_lock
<CCriticalSection
> lock(m_critical
);
477 const CProfile
*profile
= GetProfile(index
);
481 CGUIDialogYesNo
* dlgYesNo
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogYesNo
>(WINDOW_DIALOG_YES_NO
);
482 if (dlgYesNo
== NULL
)
485 const std::string
& str
= g_localizeStrings
.Get(13201);
486 dlgYesNo
->SetHeading(CVariant
{13200});
487 dlgYesNo
->SetLine(0, CVariant
{StringUtils::Format(str
, profile
->getName())});
488 dlgYesNo
->SetLine(1, CVariant
{""});
489 dlgYesNo
->SetLine(2, CVariant
{""});
492 if (!dlgYesNo
->IsConfirmed())
495 // fall back to master profile if necessary
496 if ((int)index
== m_autoLoginProfile
)
497 m_autoLoginProfile
= 0;
500 std::string strDirectory
= profile
->getDirectory();
501 m_profiles
.erase(m_profiles
.begin() + index
);
503 // fall back to master profile if necessary
504 if (index
== m_currentProfile
)
511 std::make_shared
<CFileItem
>(URIUtils::AddFileToFolder(GetUserDataFolder(), strDirectory
));
512 item
->SetPath(URIUtils::AddFileToFolder(GetUserDataFolder(), strDirectory
+ "/"));
513 item
->m_bIsFolder
= true;
516 CGUIComponent
*gui
= CServiceBroker::GetGUI();
517 if (gui
&& gui
->ConfirmDelete(item
->GetPath()))
518 CFileUtils::DeleteItem(item
);
523 void CProfileManager::CreateProfileFolders()
525 CDirectory::Create(GetDatabaseFolder());
526 CDirectory::Create(GetCDDBFolder());
527 CDirectory::Create(GetLibraryFolder());
529 // create Thumbnails/*
530 CDirectory::Create(GetThumbnailsFolder());
531 CDirectory::Create(GetVideoThumbFolder());
532 CDirectory::Create(GetBookmarksThumbFolder());
533 CDirectory::Create(GetSavestatesFolder());
534 for (size_t hex
= 0; hex
< 16; hex
++)
536 URIUtils::AddFileToFolder(GetThumbnailsFolder(), StringUtils::Format("{:x}", hex
)));
538 CDirectory::Create("special://profile/addon_data");
539 CDirectory::Create("special://profile/keymaps");
542 const CProfile
& CProfileManager::GetMasterProfile() const
544 std::unique_lock
<CCriticalSection
> lock(m_critical
);
545 if (!m_profiles
.empty())
546 return m_profiles
[0];
548 CLog::Log(LOGERROR
, "{}: master profile doesn't exist", __FUNCTION__
);
552 const CProfile
& CProfileManager::GetCurrentProfile() const
554 std::unique_lock
<CCriticalSection
> lock(m_critical
);
555 if (m_currentProfile
< m_profiles
.size())
556 return m_profiles
[m_currentProfile
];
558 CLog::Log(LOGERROR
, "CProfileManager: current profile index ({0}) is outside of the valid range ({1})", m_currentProfile
, m_profiles
.size());
562 const CProfile
* CProfileManager::GetProfile(unsigned int index
) const
564 std::unique_lock
<CCriticalSection
> lock(m_critical
);
565 if (index
< m_profiles
.size())
566 return &m_profiles
[index
];
571 CProfile
* CProfileManager::GetProfile(unsigned int index
)
573 std::unique_lock
<CCriticalSection
> lock(m_critical
);
574 if (index
< m_profiles
.size())
575 return &m_profiles
[index
];
580 int CProfileManager::GetProfileIndex(const std::string
&name
) const
582 std::unique_lock
<CCriticalSection
> lock(m_critical
);
583 for (int i
= 0; i
< static_cast<int>(m_profiles
.size()); i
++)
585 if (StringUtils::EqualsNoCase(m_profiles
[i
].getName(), name
))
592 void CProfileManager::AddProfile(const CProfile
&profile
)
595 std::unique_lock
<CCriticalSection
> lock(m_critical
);
596 // data integrity check - covers off migration from old profiles.xml,
597 // incrementing of the m_nextIdProfile,and bad data coming in
598 m_nextProfileId
= std::max(m_nextProfileId
, profile
.getId() + 1);
600 m_profiles
.push_back(profile
);
605 void CProfileManager::UpdateCurrentProfileDate()
607 std::unique_lock
<CCriticalSection
> lock(m_critical
);
608 if (m_currentProfile
< m_profiles
.size())
610 m_profiles
[m_currentProfile
].setDate();
611 CSingleExit
exit(m_critical
);
616 void CProfileManager::LoadMasterProfileForLogin()
618 std::unique_lock
<CCriticalSection
> lock(m_critical
);
619 // save the previous user
620 m_lastUsedProfile
= m_currentProfile
;
621 if (m_currentProfile
!= 0)
623 // determines that the (master) profile has only been loaded for login
624 m_profileLoadedForLogin
= true;
628 // remember that the (master) profile has only been loaded for login
629 m_previousProfileLoadedForLogin
= true;
633 bool CProfileManager::GetProfileName(const unsigned int profileId
, std::string
& name
) const
635 std::unique_lock
<CCriticalSection
> lock(m_critical
);
636 const CProfile
*profile
= GetProfile(profileId
);
640 name
= profile
->getName();
644 std::string
CProfileManager::GetUserDataFolder() const
646 return GetMasterProfile().getDirectory();
649 std::string
CProfileManager::GetProfileUserDataFolder() const
651 if (m_currentProfile
== 0)
652 return GetUserDataFolder();
654 return URIUtils::AddFileToFolder(GetUserDataFolder(), GetCurrentProfile().getDirectory());
657 std::string
CProfileManager::GetDatabaseFolder() const
659 if (GetCurrentProfile().hasDatabases())
660 return URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Database");
662 return URIUtils::AddFileToFolder(GetUserDataFolder(), "Database");
665 std::string
CProfileManager::GetCDDBFolder() const
667 return URIUtils::AddFileToFolder(GetDatabaseFolder(), "CDDB");
670 std::string
CProfileManager::GetThumbnailsFolder() const
672 if (GetCurrentProfile().hasDatabases())
673 return URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Thumbnails");
675 return URIUtils::AddFileToFolder(GetUserDataFolder(), "Thumbnails");
678 std::string
CProfileManager::GetVideoThumbFolder() const
680 return URIUtils::AddFileToFolder(GetThumbnailsFolder(), "Video");
683 std::string
CProfileManager::GetBookmarksThumbFolder() const
685 return URIUtils::AddFileToFolder(GetVideoThumbFolder(), "Bookmarks");
688 std::string
CProfileManager::GetLibraryFolder() const
690 if (GetCurrentProfile().hasDatabases())
691 return URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "library");
693 return URIUtils::AddFileToFolder(GetUserDataFolder(), "library");
696 std::string
CProfileManager::GetSavestatesFolder() const
698 if (GetCurrentProfile().hasDatabases())
699 return URIUtils::AddFileToFolder(GetProfileUserDataFolder(), "Savestates");
701 return URIUtils::AddFileToFolder(GetUserDataFolder(), "Savestates");
704 std::string
CProfileManager::GetSettingsFile() const
706 if (m_currentProfile
== 0)
707 return "special://masterprofile/guisettings.xml";
709 return "special://profile/guisettings.xml";
712 std::string
CProfileManager::GetUserDataItem(const std::string
& strFile
) const
715 path
= "special://profile/" + strFile
;
717 // check if item exists in the profile (either for folder or
718 // for a file (depending on slashAtEnd of strFile) otherwise
719 // return path to masterprofile
720 if ((URIUtils::HasSlashAtEnd(path
) && !CDirectory::Exists(path
)) || !CFile::Exists(path
))
721 path
= "special://masterprofile/" + strFile
;
726 CEventLog
& CProfileManager::GetEventLog()
728 return m_eventLogs
->GetEventLog(GetCurrentProfileId());
731 void CProfileManager::OnSettingAction(const std::shared_ptr
<const CSetting
>& setting
)
733 if (setting
== nullptr)
736 const std::string
& settingId
= setting
->GetId();
737 if (settingId
== CSettings::SETTING_EVENTLOG_SHOW
)
738 GetEventLog().ShowFullEventLog();
741 void CProfileManager::SetCurrentProfileId(unsigned int profileId
)
744 std::unique_lock
<CCriticalSection
> lock(m_critical
);
745 m_currentProfile
= profileId
;
746 CSpecialProtocol::SetProfilePath(GetProfileUserDataFolder());