diff options
Diffstat (limited to 'xbmc/settings/lib/SettingDependency.cpp')
-rw-r--r-- | xbmc/settings/lib/SettingDependency.cpp | 421 |
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; +} |