summaryrefslogtreecommitdiffstats
path: root/xbmc/settings/lib/SettingDependency.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/settings/lib/SettingDependency.cpp')
-rw-r--r--xbmc/settings/lib/SettingDependency.cpp421
1 files changed, 421 insertions, 0 deletions
diff --git a/xbmc/settings/lib/SettingDependency.cpp b/xbmc/settings/lib/SettingDependency.cpp
new file mode 100644
index 0000000..e3122da
--- /dev/null
+++ b/xbmc/settings/lib/SettingDependency.cpp
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2013-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "SettingDependency.h"
+
+#include "ServiceBroker.h"
+#include "Setting.h"
+#include "SettingDefinitions.h"
+#include "SettingsManager.h"
+#include "utils/StringUtils.h"
+#include "utils/XBMCTinyXML.h"
+#include "utils/log.h"
+
+#include <memory>
+#include <set>
+#include <stdlib.h>
+#include <string>
+
+Logger CSettingDependencyCondition::s_logger;
+
+CSettingDependencyCondition::CSettingDependencyCondition(
+ CSettingsManager* settingsManager /* = nullptr */)
+ : CSettingDependencyCondition(settingsManager, "", "", "")
+{
+}
+
+CSettingDependencyCondition::CSettingDependencyCondition(
+ const std::string& setting,
+ const std::string& value,
+ SettingDependencyOperator op,
+ bool negated /* = false */,
+ CSettingsManager* settingsManager /* = nullptr */)
+ : CSettingDependencyCondition(
+ settingsManager, setting, setting, value, SettingDependencyTarget::Setting, op, negated)
+{
+}
+
+CSettingDependencyCondition::CSettingDependencyCondition(
+ const std::string& strProperty,
+ const std::string& value,
+ const std::string& setting /* = "" */,
+ bool negated /* = false */,
+ CSettingsManager* settingsManager /* = nullptr */)
+ : CSettingDependencyCondition(settingsManager,
+ strProperty,
+ setting,
+ value,
+ SettingDependencyTarget::Property,
+ SettingDependencyOperator::Equals,
+ negated)
+{
+}
+
+CSettingDependencyCondition::CSettingDependencyCondition(
+ CSettingsManager* settingsManager,
+ const std::string& strProperty,
+ const std::string& setting,
+ const std::string& value,
+ SettingDependencyTarget target /* = SettingDependencyTarget::Unknown */,
+ SettingDependencyOperator op /* = SettingDependencyOperator::Equals */,
+ bool negated /* = false */)
+ : CSettingConditionItem(settingsManager), m_target(target), m_operator(op)
+{
+ if (s_logger == nullptr)
+ s_logger = CServiceBroker::GetLogging().GetLogger("CSettingDependencyCondition");
+
+ m_name = strProperty;
+ m_setting = setting;
+ m_value = value;
+ m_negated = negated;
+}
+
+bool CSettingDependencyCondition::Deserialize(const TiXmlNode *node)
+{
+ if (!CSettingConditionItem::Deserialize(node))
+ return false;
+
+ auto elem = node->ToElement();
+ if (elem == nullptr)
+ return false;
+
+ m_target = SettingDependencyTarget::Setting;
+ auto strTarget = elem->Attribute(SETTING_XML_ATTR_ON);
+ if (strTarget != nullptr && !setTarget(strTarget))
+ {
+ s_logger->warn("unknown target \"{}\"", strTarget);
+ return false;
+ }
+
+ if (m_target != SettingDependencyTarget::Setting && m_name.empty())
+ {
+ s_logger->warn("missing name for dependency");
+ return false;
+ }
+
+ if (m_target == SettingDependencyTarget::Setting)
+ {
+ if (m_setting.empty())
+ {
+ s_logger->warn("missing setting for dependency");
+ return false;
+ }
+
+ m_name = m_setting;
+ }
+
+ m_operator = SettingDependencyOperator::Equals;
+ auto strOperator = elem->Attribute(SETTING_XML_ATTR_OPERATOR);
+ if (strOperator != nullptr && !setOperator(strOperator))
+ {
+ s_logger->warn("unknown operator \"{}\"", strOperator);
+ return false;
+ }
+
+ return true;
+}
+
+bool CSettingDependencyCondition::Check() const
+{
+ if (m_name.empty() ||
+ m_target == SettingDependencyTarget::Unknown ||
+ m_operator == SettingDependencyOperator::Unknown ||
+ m_settingsManager == nullptr)
+ return false;
+
+ bool result = false;
+ switch (m_target)
+ {
+ case SettingDependencyTarget::Setting:
+ {
+ if (m_setting.empty())
+ return false;
+
+ auto setting = m_settingsManager->GetSetting(m_setting);
+ if (setting == nullptr)
+ {
+ s_logger->warn("unable to check condition on unknown setting \"{}\"", m_setting);
+ return false;
+ }
+
+ switch (m_operator)
+ {
+ case SettingDependencyOperator::Equals:
+ result = setting->Equals(m_value);
+ break;
+
+ case SettingDependencyOperator::LessThan:
+ {
+ const auto value = setting->ToString();
+ if (StringUtils::IsInteger(m_value))
+ result = strtol(value.c_str(), nullptr, 0) < strtol(m_value.c_str(), nullptr, 0);
+ else
+ result = value.compare(m_value) < 0;
+ break;
+ }
+
+ case SettingDependencyOperator::GreaterThan:
+ {
+ const auto value = setting->ToString();
+ if (StringUtils::IsInteger(m_value))
+ result = strtol(value.c_str(), nullptr, 0) > strtol(m_value.c_str(), nullptr, 0);
+ else
+ result = value.compare(m_value) > 0;
+ break;
+ }
+
+ case SettingDependencyOperator::Contains:
+ result = (setting->ToString().find(m_value) != std::string::npos);
+ break;
+
+ case SettingDependencyOperator::Unknown:
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ case SettingDependencyTarget::Property:
+ {
+ SettingConstPtr setting;
+ if (!m_setting.empty())
+ {
+ setting = m_settingsManager->GetSetting(m_setting);
+ if (setting == nullptr)
+ {
+ s_logger->warn("unable to check condition on unknown setting \"{}\"", m_setting);
+ return false;
+ }
+ }
+ result = m_settingsManager->GetConditions().Check(m_name, m_value, setting);
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ return result == !m_negated;
+}
+
+bool CSettingDependencyCondition::setTarget(const std::string &target)
+{
+ if (StringUtils::EqualsNoCase(target, "setting"))
+ m_target = SettingDependencyTarget::Setting;
+ else if (StringUtils::EqualsNoCase(target, "property"))
+ m_target = SettingDependencyTarget::Property;
+ else
+ return false;
+
+ return true;
+}
+
+bool CSettingDependencyCondition::setOperator(const std::string &op)
+{
+ size_t length = 0;
+ if (StringUtils::EndsWithNoCase(op, "is"))
+ {
+ m_operator = SettingDependencyOperator::Equals;
+ length = 2;
+ }
+ else if (StringUtils::EndsWithNoCase(op, "lessthan"))
+ {
+ m_operator = SettingDependencyOperator::LessThan;
+ length = 8;
+ }
+ else if (StringUtils::EndsWithNoCase(op, "lt"))
+ {
+ m_operator = SettingDependencyOperator::LessThan;
+ length = 2;
+ }
+ else if (StringUtils::EndsWithNoCase(op, "greaterthan"))
+ {
+ m_operator = SettingDependencyOperator::GreaterThan;
+ length = 11;
+ }
+ else if (StringUtils::EndsWithNoCase(op, "gt"))
+ {
+ m_operator = SettingDependencyOperator::GreaterThan;
+ length = 2;
+ }
+ else if (StringUtils::EndsWithNoCase(op, "contains"))
+ {
+ m_operator = SettingDependencyOperator::Contains;
+ length = 8;
+ }
+
+ if (op.size() > length + 1)
+ return false;
+ if (op.size() == length + 1)
+ {
+ if (!StringUtils::StartsWith(op, "!"))
+ return false;
+ m_negated = true;
+ }
+
+ return true;
+}
+
+bool CSettingDependencyConditionCombination::Deserialize(const TiXmlNode *node)
+{
+ if (node == nullptr)
+ return false;
+
+ size_t numOperations = m_operations.size();
+ size_t numValues = m_values.size();
+
+ if (!CSettingConditionCombination::Deserialize(node))
+ return false;
+
+ if (numOperations < m_operations.size())
+ {
+ for (size_t i = numOperations; i < m_operations.size(); i++)
+ {
+ if (m_operations[i] == nullptr)
+ continue;
+
+ auto combination = static_cast<CSettingDependencyConditionCombination*>(m_operations[i].get());
+ if (combination == nullptr)
+ continue;
+
+ const std::set<std::string>& settings = combination->GetSettings();
+ m_settings.insert(settings.begin(), settings.end());
+ }
+ }
+
+ if (numValues < m_values.size())
+ {
+ for (size_t i = numValues; i < m_values.size(); i++)
+ {
+ if (m_values[i] == nullptr)
+ continue;
+
+ auto condition = static_cast<CSettingDependencyCondition*>(m_values[i].get());
+ if (condition == nullptr)
+ continue;
+
+ auto settingId = condition->GetSetting();
+ if (!settingId.empty())
+ m_settings.insert(settingId);
+ }
+ }
+
+ return true;
+}
+
+CSettingDependencyConditionCombination* CSettingDependencyConditionCombination::Add(
+ const CSettingDependencyConditionPtr& condition)
+{
+ if (condition != nullptr)
+ {
+ m_values.push_back(condition);
+
+ auto settingId = condition->GetSetting();
+ if (!settingId.empty())
+ m_settings.insert(settingId);
+ }
+
+ return this;
+}
+
+CSettingDependencyConditionCombination* CSettingDependencyConditionCombination::Add(
+ const CSettingDependencyConditionCombinationPtr& operation)
+{
+ if (operation != nullptr)
+ {
+ m_operations.push_back(operation);
+
+ const auto& settings = operation->GetSettings();
+ m_settings.insert(settings.begin(), settings.end());
+ }
+
+ return this;
+}
+
+Logger CSettingDependency::s_logger;
+
+CSettingDependency::CSettingDependency(CSettingsManager* settingsManager /* = nullptr */)
+ : CSettingDependency(SettingDependencyType::Unknown, settingsManager)
+{
+}
+
+CSettingDependency::CSettingDependency(SettingDependencyType type,
+ CSettingsManager* settingsManager /* = nullptr */)
+ : CSettingCondition(settingsManager), m_type(type)
+{
+ if (s_logger == nullptr)
+ s_logger = CServiceBroker::GetLogging().GetLogger("CSettingDependency");
+
+ m_operation = CBooleanLogicOperationPtr(new CSettingDependencyConditionCombination(m_settingsManager));
+}
+
+bool CSettingDependency::Deserialize(const TiXmlNode *node)
+{
+ if (node == nullptr)
+ return false;
+
+ auto elem = node->ToElement();
+ if (elem == nullptr)
+ return false;
+
+ auto strType = elem->Attribute(SETTING_XML_ATTR_TYPE);
+ if (strType == nullptr || strlen(strType) <= 0 || !setType(strType))
+ {
+ s_logger->warn("missing or unknown dependency type definition");
+ return false;
+ }
+
+ return CSettingCondition::Deserialize(node);
+}
+
+std::set<std::string> CSettingDependency::GetSettings() const
+{
+ if (m_operation == nullptr)
+ return std::set<std::string>();
+
+ auto combination = static_cast<CSettingDependencyConditionCombination*>(m_operation.get());
+ if (combination == nullptr)
+ return std::set<std::string>();
+
+ return combination->GetSettings();
+}
+
+CSettingDependencyConditionCombinationPtr CSettingDependency::And()
+{
+ if (m_operation == nullptr)
+ m_operation = CBooleanLogicOperationPtr(new CSettingDependencyConditionCombination(m_settingsManager));
+
+ m_operation->SetOperation(BooleanLogicOperationAnd);
+
+ return std::dynamic_pointer_cast<CSettingDependencyConditionCombination>(m_operation);
+}
+
+CSettingDependencyConditionCombinationPtr CSettingDependency::Or()
+{
+ if (m_operation == nullptr)
+ m_operation = CBooleanLogicOperationPtr(new CSettingDependencyConditionCombination(m_settingsManager));
+
+ m_operation->SetOperation(BooleanLogicOperationOr);
+
+ return std::dynamic_pointer_cast<CSettingDependencyConditionCombination>(m_operation);
+}
+
+bool CSettingDependency::setType(const std::string &type)
+{
+ if (StringUtils::EqualsNoCase(type, "enable"))
+ m_type = SettingDependencyType::Enable;
+ else if (StringUtils::EqualsNoCase(type, "update"))
+ m_type = SettingDependencyType::Update;
+ else if (StringUtils::EqualsNoCase(type, "visible"))
+ m_type = SettingDependencyType::Visible;
+ else
+ return false;
+
+ return true;
+}