1 /*
2  *  Copyright (C) 2015-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "PVRSettings.h"
10 
11 #include "ServiceBroker.h"
12 #include "guilib/LocalizeStrings.h"
13 #include "pvr/PVRManager.h"
14 #include "pvr/addons/PVRClients.h"
15 #include "pvr/guilib/PVRGUIActions.h"
16 #include "settings/Settings.h"
17 #include "settings/SettingsComponent.h"
18 #include "settings/lib/SettingsManager.h"
19 #include "utils/StringUtils.h"
20 #include "utils/log.h"
21 
22 #include <memory>
23 #include <set>
24 #include <string>
25 #include <utility>
26 
27 using namespace PVR;
28 
29 unsigned int CPVRSettings::m_iInstances = 0;
30 
CPVRSettings(const std::set<std::string> & settingNames)31 CPVRSettings::CPVRSettings(const std::set<std::string>& settingNames)
32 {
33   Init(settingNames);
34 
35   const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
36   settings->GetSettingsManager()->RegisterSettingsHandler(this);
37   settings->RegisterCallback(this, settingNames);
38 
39   if (m_iInstances == 0)
40   {
41     // statics must only be registered once, not per instance
42     settings->GetSettingsManager()->RegisterSettingOptionsFiller("pvrrecordmargins", MarginTimeFiller);
43     settings->GetSettingsManager()->AddDynamicCondition("pvrsettingvisible", IsSettingVisible);
44     settings->GetSettingsManager()->AddDynamicCondition("checkpvrparentalpin", CheckParentalPin);
45   }
46   m_iInstances++;
47 }
48 
~CPVRSettings()49 CPVRSettings::~CPVRSettings()
50 {
51   const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
52 
53   m_iInstances--;
54   if (m_iInstances == 0)
55   {
56     settings->GetSettingsManager()->RemoveDynamicCondition("checkpvrparentalpin");
57     settings->GetSettingsManager()->RemoveDynamicCondition("pvrsettingvisible");
58     settings->GetSettingsManager()->UnregisterSettingOptionsFiller("pvrrecordmargins");
59   }
60 
61   settings->UnregisterCallback(this);
62   settings->GetSettingsManager()->UnregisterSettingsHandler(this);
63 }
64 
Init(const std::set<std::string> & settingNames)65 void CPVRSettings::Init(const std::set<std::string>& settingNames)
66 {
67   for (auto settingName : settingNames)
68   {
69     SettingPtr setting = CServiceBroker::GetSettingsComponent()->GetSettings()->GetSetting(settingName);
70     if (!setting)
71     {
72       CLog::LogF(LOGERROR, "Unknown PVR setting '{}'", settingName);
73       continue;
74     }
75 
76     CSingleLock lock(m_critSection);
77     m_settings.insert(std::make_pair(settingName, setting->Clone(settingName)));
78   }
79 }
80 
OnSettingsLoaded()81 void CPVRSettings::OnSettingsLoaded()
82 {
83   std::set<std::string> settingNames;
84 
85   {
86     CSingleLock lock(m_critSection);
87     for (const auto& settingName : m_settings)
88       settingNames.insert(settingName.first);
89 
90     m_settings.clear();
91   }
92 
93   Init(settingNames);
94 }
95 
OnSettingChanged(const std::shared_ptr<const CSetting> & setting)96 void CPVRSettings::OnSettingChanged(const std::shared_ptr<const CSetting>& setting)
97 {
98   if (setting == nullptr)
99     return;
100 
101   CSingleLock lock(m_critSection);
102   m_settings[setting->GetId()] = setting->Clone(setting->GetId());
103 }
104 
GetBoolValue(const std::string & settingName) const105 bool CPVRSettings::GetBoolValue(const std::string& settingName) const
106 {
107   CSingleLock lock(m_critSection);
108   auto settingIt = m_settings.find(settingName);
109   if (settingIt != m_settings.end() && (*settingIt).second->GetType() == SettingType::Boolean)
110   {
111     std::shared_ptr<const CSettingBool> setting = std::dynamic_pointer_cast<const CSettingBool>((*settingIt).second);
112     if (setting)
113       return setting->GetValue();
114   }
115 
116   CLog::LogF(LOGERROR, "PVR setting '{}' not found or wrong type given", settingName);
117   return false;
118 }
119 
GetIntValue(const std::string & settingName) const120 int CPVRSettings::GetIntValue(const std::string& settingName) const
121 {
122   CSingleLock lock(m_critSection);
123   auto settingIt = m_settings.find(settingName);
124   if (settingIt != m_settings.end() && (*settingIt).second->GetType() == SettingType::Integer)
125   {
126     std::shared_ptr<const CSettingInt> setting = std::dynamic_pointer_cast<const CSettingInt>((*settingIt).second);
127     if (setting)
128       return setting->GetValue();
129   }
130 
131   CLog::LogF(LOGERROR, "PVR setting '{}' not found or wrong type given", settingName);
132   return -1;
133 }
134 
GetStringValue(const std::string & settingName) const135 std::string CPVRSettings::GetStringValue(const std::string& settingName) const
136 {
137   CSingleLock lock(m_critSection);
138   auto settingIt = m_settings.find(settingName);
139   if (settingIt != m_settings.end() && (*settingIt).second->GetType() == SettingType::String)
140   {
141     std::shared_ptr<const CSettingString> setting = std::dynamic_pointer_cast<const CSettingString>((*settingIt).second);
142     if (setting)
143       return setting->GetValue();
144   }
145 
146   CLog::LogF(LOGERROR, "PVR setting '{}' not found or wrong type given", settingName);
147   return "";
148 }
149 
MarginTimeFiller(const SettingConstPtr &,std::vector<IntegerSettingOption> & list,int & current,void *)150 void CPVRSettings::MarginTimeFiller(const SettingConstPtr& /*setting*/,
151                                     std::vector<IntegerSettingOption>& list,
152                                     int& current,
153                                     void* /*data*/)
154 {
155   list.clear();
156 
157   static const int marginTimeValues[] =
158   {
159     0, 1, 3, 5, 10, 15, 20, 30, 60, 90, 120, 180 // minutes
160   };
161 
162   for (int iValue : marginTimeValues)
163   {
164     list.emplace_back(StringUtils::Format(g_localizeStrings.Get(14044).c_str(), iValue) /* %i min */, iValue);
165   }
166 }
167 
IsSettingVisible(const std::string & condition,const std::string & value,const std::shared_ptr<const CSetting> & setting,void * data)168 bool CPVRSettings::IsSettingVisible(const std::string& condition,
169                                     const std::string& value,
170                                     const std::shared_ptr<const CSetting>& setting,
171                                     void* data)
172 {
173   if (setting == nullptr)
174     return false;
175 
176   const std::string& settingId = setting->GetId();
177 
178   if (settingId == CSettings::SETTING_PVRMANAGER_USEBACKENDCHANNELNUMBERS)
179   {
180     // Setting is only visible if exactly one PVR client is enabled or
181     // the expert setting to always use backend numbers is enabled
182     const auto& settings = CServiceBroker::GetSettingsComponent()->GetSettings();
183     int enabledClientAmount = CServiceBroker::GetPVRManager().Clients()->EnabledClientAmount();
184 
185     return enabledClientAmount == 1 ||
186            (settings->GetBool(CSettings::SETTING_PVRMANAGER_USEBACKENDCHANNELNUMBERSALWAYS) &&
187             enabledClientAmount > 1);
188   }
189   else if (settingId == CSettings::SETTING_PVRMANAGER_USEBACKENDCHANNELNUMBERSALWAYS)
190   {
191     // Setting is only visible if more than one PVR client is enabled.
192     return CServiceBroker::GetPVRManager().Clients()->EnabledClientAmount() > 1;
193   }
194   else if (settingId == CSettings::SETTING_PVRMANAGER_CLIENTPRIORITIES)
195   {
196     // Setting is only visible if more than one PVR client is enabeld.
197     return CServiceBroker::GetPVRManager().Clients()->EnabledClientAmount() > 1;
198   }
199   else
200   {
201     // Show all other settings unconditionally.
202     return true;
203   }
204 }
205 
CheckParentalPin(const std::string & condition,const std::string & value,const std::shared_ptr<const CSetting> & setting,void * data)206 bool CPVRSettings::CheckParentalPin(const std::string& condition,
207                                     const std::string& value,
208                                     const std::shared_ptr<const CSetting>& setting,
209                                     void* data)
210 {
211   return CServiceBroker::GetPVRManager().GUIActions()->CheckParentalPIN() == ParentalCheckResult::SUCCESS;
212 }
213