summaryrefslogtreecommitdiffstats
path: root/xbmc/settings/lib/SettingSection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/settings/lib/SettingSection.cpp')
-rw-r--r--xbmc/settings/lib/SettingSection.cpp359
1 files changed, 359 insertions, 0 deletions
diff --git a/xbmc/settings/lib/SettingSection.cpp b/xbmc/settings/lib/SettingSection.cpp
new file mode 100644
index 0000000..4f1b564
--- /dev/null
+++ b/xbmc/settings/lib/SettingSection.cpp
@@ -0,0 +1,359 @@
+/*
+ * 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 "SettingSection.h"
+
+#include "ServiceBroker.h"
+#include "SettingDefinitions.h"
+#include "SettingsManager.h"
+#include "utils/StringUtils.h"
+#include "utils/XBMCTinyXML.h"
+#include "utils/log.h"
+
+#include <algorithm>
+
+template<class T>
+void addISetting(const TiXmlNode* node, const T& item, std::vector<T>& items, bool toBegin = false)
+{
+ if (node != nullptr)
+ {
+ auto element = node->ToElement();
+ if (element != nullptr)
+ {
+ // check if there is a "before" or "after" attribute to place the setting at a specific position
+ int position = -1; // -1 => end, 0 => before, 1 => after
+ auto positionId = element->Attribute(SETTING_XML_ATTR_BEFORE);
+ if (positionId != nullptr && strlen(positionId) > 0)
+ position = 0;
+ else if ((positionId = element->Attribute(SETTING_XML_ATTR_AFTER)) != nullptr && strlen(positionId) > 0)
+ position = 1;
+
+ if (positionId != nullptr && strlen(positionId) > 0 && position >= 0)
+ {
+ for (typename std::vector<T>::iterator it = items.begin(); it != items.end(); ++it)
+ {
+ if (!StringUtils::EqualsNoCase((*it)->GetId(), positionId))
+ continue;
+
+ typename std::vector<T>::iterator positionIt = it;
+ if (position == 1)
+ ++positionIt;
+
+ items.insert(positionIt, item);
+ return;
+ }
+ }
+ }
+ }
+
+ if (!toBegin)
+ items.emplace_back(item);
+ else
+ items.insert(items.begin(), item);
+}
+
+Logger CSettingGroup::s_logger;
+
+CSettingGroup::CSettingGroup(const std::string& id,
+ CSettingsManager* settingsManager /* = nullptr */)
+ : ISetting(id, settingsManager)
+{
+ if (s_logger == nullptr)
+ s_logger = CServiceBroker::GetLogging().GetLogger("CSettingGroup");
+}
+
+bool CSettingGroup::Deserialize(const TiXmlNode *node, bool update /* = false */)
+{
+ // handle <visible> conditions
+ if (!ISetting::Deserialize(node, update))
+ return false;
+
+ auto controlElement = node->FirstChildElement(SETTING_XML_ELM_CONTROL);
+ if (controlElement != nullptr)
+ {
+ auto controlType = controlElement->Attribute(SETTING_XML_ATTR_TYPE);
+ if (controlType == nullptr || strlen(controlType) <= 0)
+ {
+ s_logger->error("unable to read control type");
+ return false;
+ }
+
+ m_control = m_settingsManager->CreateControl(controlType);
+ if (m_control == nullptr)
+ {
+ s_logger->error("unable to create new control \"{}\"", controlType);
+ return false;
+ }
+
+ if (!m_control->Deserialize(controlElement))
+ {
+ s_logger->warn("unable to read control \"{}\"", controlType);
+ m_control.reset();
+ }
+ }
+
+ auto settingElement = node->FirstChildElement(SETTING_XML_ELM_SETTING);
+ while (settingElement != nullptr)
+ {
+ std::string settingId;
+ bool isReference;
+ if (CSetting::DeserializeIdentification(settingElement, settingId, isReference))
+ {
+ auto settingIt = std::find_if(m_settings.begin(), m_settings.end(),
+ [&settingId](const SettingPtr& setting)
+ {
+ return setting->GetId() == settingId;
+ });
+
+ SettingPtr setting;
+ if (settingIt != m_settings.end())
+ setting = *settingIt;
+
+ update = (setting != nullptr);
+ if (!update)
+ {
+ auto settingType = settingElement->Attribute(SETTING_XML_ATTR_TYPE);
+ if (settingType == nullptr || strlen(settingType) <= 0)
+ {
+ s_logger->error("unable to read setting type of \"{}\"", settingId);
+ return false;
+ }
+
+ setting = m_settingsManager->CreateSetting(settingType, settingId, m_settingsManager);
+ if (setting == nullptr)
+ s_logger->error("unknown setting type \"{}\" of \"{}\"", settingType, settingId);
+ }
+
+ if (setting == nullptr)
+ s_logger->error("unable to create new setting \"{}\"", settingId);
+ else
+ {
+ if (!setting->Deserialize(settingElement, update))
+ s_logger->warn("unable to read setting \"{}\"", settingId);
+ else
+ {
+ // if the setting is a reference turn it into one
+ if (isReference)
+ setting->MakeReference();
+
+ if (!update)
+ addISetting(settingElement, setting, m_settings);
+ }
+ }
+ }
+
+ settingElement = settingElement->NextSiblingElement(SETTING_XML_ELM_SETTING);
+ }
+
+ return true;
+}
+
+SettingList CSettingGroup::GetSettings(SettingLevel level) const
+{
+ SettingList settings;
+ for (const auto& setting : m_settings)
+ {
+ if (setting->GetLevel() <= level && setting->MeetsRequirements())
+ settings.push_back(setting);
+ }
+
+ return settings;
+}
+
+void CSettingGroup::AddSetting(const SettingPtr& setting)
+{
+ addISetting(nullptr, setting, m_settings);
+}
+
+void CSettingGroup::AddSettings(const SettingList &settings)
+{
+ for (const auto& setting : settings)
+ addISetting(nullptr, setting, m_settings);
+}
+
+bool CSettingGroup::ReplaceSetting(const std::shared_ptr<const CSetting>& currentSetting,
+ const std::shared_ptr<CSetting>& newSetting)
+{
+ for (auto itSetting = m_settings.begin(); itSetting != m_settings.end(); ++itSetting)
+ {
+ if (*itSetting == currentSetting)
+ {
+ if (newSetting == nullptr)
+ m_settings.erase(itSetting);
+ else
+ *itSetting = newSetting;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Logger CSettingCategory::s_logger;
+
+CSettingCategory::CSettingCategory(const std::string& id,
+ CSettingsManager* settingsManager /* = nullptr */)
+ : ISetting(id, settingsManager),
+ m_accessCondition(settingsManager)
+{
+ if (s_logger == nullptr)
+ s_logger = CServiceBroker::GetLogging().GetLogger("CSettingCategory");
+}
+
+bool CSettingCategory::Deserialize(const TiXmlNode *node, bool update /* = false */)
+{
+ // handle <visible> conditions
+ if (!ISetting::Deserialize(node, update))
+ return false;
+
+ auto accessNode = node->FirstChild(SETTING_XML_ELM_ACCESS);
+ if (accessNode != nullptr && !m_accessCondition.Deserialize(accessNode))
+ return false;
+
+ auto groupNode = node->FirstChild(SETTING_XML_ELM_GROUP);
+ while (groupNode != nullptr)
+ {
+ std::string groupId;
+ if (CSettingGroup::DeserializeIdentification(groupNode, groupId))
+ {
+ auto groupIt = std::find_if(m_groups.begin(), m_groups.end(),
+ [&groupId](const SettingGroupPtr& group)
+ {
+ return group->GetId() == groupId;
+ });
+
+ SettingGroupPtr group;
+ if (groupIt != m_groups.end())
+ group = *groupIt;
+
+ update = (group != nullptr);
+ if (!update)
+ group = std::make_shared<CSettingGroup>(groupId, m_settingsManager);
+
+ if (group->Deserialize(groupNode, update))
+ {
+ if (!update)
+ addISetting(groupNode, group, m_groups);
+ }
+ else
+ s_logger->warn("unable to read group \"{}\"", groupId);
+ }
+
+ groupNode = groupNode->NextSibling(SETTING_XML_ELM_GROUP);
+ }
+
+ return true;
+}
+
+SettingGroupList CSettingCategory::GetGroups(SettingLevel level) const
+{
+ SettingGroupList groups;
+ for (const auto& group : m_groups)
+ {
+ if (group->MeetsRequirements() && group->IsVisible() && group->GetSettings(level).size() > 0)
+ groups.push_back(group);
+ }
+
+ return groups;
+}
+
+bool CSettingCategory::CanAccess() const
+{
+ return m_accessCondition.Check();
+}
+
+void CSettingCategory::AddGroup(const SettingGroupPtr& group)
+{
+ addISetting(nullptr, group, m_groups, false);
+}
+
+void CSettingCategory::AddGroupToFront(const SettingGroupPtr& group)
+{
+ addISetting(nullptr, group, m_groups, true);
+}
+
+void CSettingCategory::AddGroups(const SettingGroupList &groups)
+{
+ for (const auto& group : groups)
+ addISetting(nullptr, group, m_groups);
+}
+
+Logger CSettingSection::s_logger;
+
+CSettingSection::CSettingSection(const std::string& id,
+ CSettingsManager* settingsManager /* = nullptr */)
+ : ISetting(id, settingsManager)
+{
+ if (s_logger == nullptr)
+ s_logger = CServiceBroker::GetLogging().GetLogger("CSettingSection");
+}
+
+bool CSettingSection::Deserialize(const TiXmlNode *node, bool update /* = false */)
+{
+ // handle <visible> conditions
+ if (!ISetting::Deserialize(node, update))
+ return false;
+
+ auto categoryNode = node->FirstChild(SETTING_XML_ELM_CATEGORY);
+ while (categoryNode != nullptr)
+ {
+ std::string categoryId;
+ if (CSettingCategory::DeserializeIdentification(categoryNode, categoryId))
+ {
+ auto categoryIt = std::find_if(m_categories.begin(), m_categories.end(),
+ [&categoryId](const SettingCategoryPtr& category)
+ {
+ return category->GetId() == categoryId;
+ });
+
+ SettingCategoryPtr category;
+ if (categoryIt != m_categories.end())
+ category = *categoryIt;
+
+ update = (category != nullptr);
+ if (!update)
+ category = std::make_shared<CSettingCategory>(categoryId, m_settingsManager);
+
+ if (category->Deserialize(categoryNode, update))
+ {
+ if (!update)
+ addISetting(categoryNode, category, m_categories);
+ }
+ else
+ s_logger->warn("unable to read category \"{}\"", categoryId);
+ }
+
+ categoryNode = categoryNode->NextSibling(SETTING_XML_ELM_CATEGORY);
+ }
+
+ return true;
+}
+
+SettingCategoryList CSettingSection::GetCategories(SettingLevel level) const
+{
+ SettingCategoryList categories;
+ for (const auto& category : m_categories)
+ {
+ if (category->MeetsRequirements() && category->IsVisible() && category->GetGroups(level).size() > 0)
+ categories.push_back(category);
+ }
+
+ return categories;
+}
+
+void CSettingSection::AddCategory(const SettingCategoryPtr& category)
+{
+ addISetting(nullptr, category, m_categories);
+}
+
+void CSettingSection::AddCategories(const SettingCategoryList &categories)
+{
+ for (const auto& category : categories)
+ addISetting(nullptr, category, m_categories);
+}