/*
* Copyright (C) 2013 Team XBMC
* http://xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, see
* .
*
*/
#include "SettingsOperations.h"
#include "addons/Addon.h"
#include "settings/SettingAddon.h"
#include "settings/SettingControl.h"
#include "settings/SettingPath.h"
#include "settings/Settings.h"
#include "settings/SettingUtils.h"
#include "settings/lib/Setting.h"
#include "settings/lib/SettingSection.h"
#include "guilib/LocalizeStrings.h"
#include "utils/StringUtils.h"
using namespace std;
using namespace JSONRPC;
JSONRPC_STATUS CSettingsOperations::GetSections(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
{
SettingLevel level = (SettingLevel)ParseSettingLevel(parameterObject["level"].asString());
bool listCategories = !parameterObject["properties"].empty() && parameterObject["properties"][0].asString() == "categories";
result["sections"] = CVariant(CVariant::VariantTypeArray);
// apply the level filter
vector allSections = CSettings::Get().GetSections();
for (vector::const_iterator itSection = allSections.begin(); itSection != allSections.end(); ++itSection)
{
SettingCategoryList categories = (*itSection)->GetCategories(level);
if (categories.empty())
continue;
CVariant varSection(CVariant::VariantTypeObject);
if (!SerializeSettingSection(*itSection, varSection))
continue;
if (listCategories)
{
varSection["categories"] = CVariant(CVariant::VariantTypeArray);
for (SettingCategoryList::const_iterator itCategory = categories.begin(); itCategory != categories.end(); ++itCategory)
{
CVariant varCategory(CVariant::VariantTypeObject);
if (!SerializeSettingCategory(*itCategory, varCategory))
continue;
varSection["categories"].push_back(varCategory);
}
}
result["sections"].push_back(varSection);
}
return OK;
}
JSONRPC_STATUS CSettingsOperations::GetCategories(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
{
SettingLevel level = (SettingLevel)ParseSettingLevel(parameterObject["level"].asString());
std::string strSection = parameterObject["section"].asString();
bool listSettings = !parameterObject["properties"].empty() && parameterObject["properties"][0].asString() == "settings";
vector sections;
if (!strSection.empty())
{
CSettingSection *section = CSettings::Get().GetSection(strSection);
if (section == NULL)
return InvalidParams;
sections.push_back(section);
}
else
sections = CSettings::Get().GetSections();
result["categories"] = CVariant(CVariant::VariantTypeArray);
for (vector::const_iterator itSection = sections.begin(); itSection != sections.end(); ++itSection)
{
SettingCategoryList categories = (*itSection)->GetCategories(level);
for (SettingCategoryList::const_iterator itCategory = categories.begin(); itCategory != categories.end(); ++itCategory)
{
CVariant varCategory(CVariant::VariantTypeObject);
if (!SerializeSettingCategory(*itCategory, varCategory))
continue;
if (listSettings)
{
varCategory["groups"] = CVariant(CVariant::VariantTypeArray);
SettingGroupList groups = (*itCategory)->GetGroups(level);
for (SettingGroupList::const_iterator itGroup = groups.begin(); itGroup != groups.end(); ++itGroup)
{
CVariant varGroup(CVariant::VariantTypeObject);
if (!SerializeSettingGroup(*itGroup, varGroup))
continue;
varGroup["settings"] = CVariant(CVariant::VariantTypeArray);
SettingList settings = (*itGroup)->GetSettings(level);
for (SettingList::const_iterator itSetting = settings.begin(); itSetting != settings.end(); ++itSetting)
{
if ((*itSetting)->IsVisible())
{
CVariant varSetting(CVariant::VariantTypeObject);
if (!SerializeSetting(*itSetting, varSetting))
continue;
varGroup["settings"].push_back(varSetting);
}
}
varCategory["groups"].push_back(varGroup);
}
}
result["categories"].push_back(varCategory);
}
}
return OK;
}
JSONRPC_STATUS CSettingsOperations::GetSettings(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
{
SettingLevel level = (SettingLevel)ParseSettingLevel(parameterObject["level"].asString());
const CVariant &filter = parameterObject["filter"];
bool doFilter = filter.isObject() && filter.isMember("section") && filter.isMember("category");
string strSection, strCategory;
if (doFilter)
{
strSection = filter["section"].asString();
strCategory = filter["category"].asString();
}
vector sections;
if (doFilter)
{
CSettingSection *section = CSettings::Get().GetSection(strSection);
if (section == NULL)
return InvalidParams;
sections.push_back(section);
}
else
sections = CSettings::Get().GetSections();
result["settings"] = CVariant(CVariant::VariantTypeArray);
for (vector::const_iterator itSection = sections.begin(); itSection != sections.end(); ++itSection)
{
SettingCategoryList categories = (*itSection)->GetCategories(level);
bool found = !doFilter;
for (SettingCategoryList::const_iterator itCategory = categories.begin(); itCategory != categories.end(); ++itCategory)
{
if (!doFilter || StringUtils::EqualsNoCase((*itCategory)->GetId(), strCategory))
{
SettingGroupList groups = (*itCategory)->GetGroups(level);
for (SettingGroupList::const_iterator itGroup = groups.begin(); itGroup != groups.end(); ++itGroup)
{
SettingList settings = (*itGroup)->GetSettings(level);
for (SettingList::const_iterator itSetting = settings.begin(); itSetting != settings.end(); ++itSetting)
{
if ((*itSetting)->IsVisible())
{
CVariant varSetting(CVariant::VariantTypeObject);
if (!SerializeSetting(*itSetting, varSetting))
continue;
result["settings"].push_back(varSetting);
}
}
}
found = true;
if (doFilter)
break;
}
}
if (doFilter && !found)
return InvalidParams;
}
return OK;
}
JSONRPC_STATUS CSettingsOperations::GetSettingValue(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
{
string settingId = parameterObject["setting"].asString();
CSetting* setting = CSettings::Get().GetSetting(settingId);
if (setting == NULL ||
!setting->IsVisible())
return InvalidParams;
CVariant value;
switch (setting->GetType())
{
case SettingTypeBool:
value = static_cast(setting)->GetValue();
break;
case SettingTypeInteger:
value = static_cast(setting)->GetValue();
break;
case SettingTypeNumber:
value = static_cast(setting)->GetValue();
break;
case SettingTypeString:
value = static_cast(setting)->GetValue();
break;
case SettingTypeList:
{
SerializeSettingListValues(CSettings::Get().GetList(settingId), value);
break;
}
case SettingTypeNone:
case SettingTypeAction:
default:
return InvalidParams;
}
result["value"] = value;
return OK;
}
JSONRPC_STATUS CSettingsOperations::SetSettingValue(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
{
string settingId = parameterObject["setting"].asString();
CVariant value = parameterObject["value"];
CSetting* setting = CSettings::Get().GetSetting(settingId);
if (setting == NULL ||
!setting->IsVisible())
return InvalidParams;
switch (setting->GetType())
{
case SettingTypeBool:
if (!value.isBoolean())
return InvalidParams;
result = static_cast(setting)->SetValue(value.asBoolean());
break;
case SettingTypeInteger:
if (!value.isInteger() && !value.isUnsignedInteger())
return InvalidParams;
result = static_cast(setting)->SetValue((int)value.asInteger());
break;
case SettingTypeNumber:
if (!value.isDouble())
return InvalidParams;
result = static_cast(setting)->SetValue(value.asDouble());
break;
case SettingTypeString:
if (!value.isString())
return InvalidParams;
result = static_cast(setting)->SetValue(value.asString());
break;
case SettingTypeList:
{
if (!value.isArray())
return InvalidParams;
std::vector values;
for (CVariant::const_iterator_array itValue = value.begin_array(); itValue != value.end_array(); ++itValue)
values.push_back(*itValue);
result = CSettings::Get().SetList(settingId, values);
break;
}
case SettingTypeNone:
case SettingTypeAction:
default:
return InvalidParams;
}
return OK;
}
JSONRPC_STATUS CSettingsOperations::ResetSettingValue(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result)
{
string settingId = parameterObject["setting"].asString();
CSetting* setting = CSettings::Get().GetSetting(settingId);
if (setting == NULL ||
!setting->IsVisible())
return InvalidParams;
switch (setting->GetType())
{
case SettingTypeBool:
case SettingTypeInteger:
case SettingTypeNumber:
case SettingTypeString:
case SettingTypeList:
setting->Reset();
break;
case SettingTypeNone:
case SettingTypeAction:
default:
return InvalidParams;
}
return ACK;
}
int CSettingsOperations::ParseSettingLevel(const std::string &strLevel)
{
if (StringUtils::EqualsNoCase(strLevel, "basic"))
return SettingLevelBasic;
if (StringUtils::EqualsNoCase(strLevel, "advanced"))
return SettingLevelAdvanced;
if (StringUtils::EqualsNoCase(strLevel, "expert"))
return SettingLevelExpert;
return SettingLevelStandard;
}
bool CSettingsOperations::SerializeISetting(const ISetting* setting, CVariant &obj)
{
if (setting == NULL)
return false;
obj["id"] = setting->GetId();
return true;
}
bool CSettingsOperations::SerializeSettingSection(const CSettingSection* setting, CVariant &obj)
{
if (!SerializeISetting(setting, obj))
return false;
obj["label"] = g_localizeStrings.Get(setting->GetLabel());
if (setting->GetHelp() >= 0)
obj["help"] = g_localizeStrings.Get(setting->GetHelp());
return true;
}
bool CSettingsOperations::SerializeSettingCategory(const CSettingCategory* setting, CVariant &obj)
{
if (!SerializeISetting(setting, obj))
return false;
obj["label"] = g_localizeStrings.Get(setting->GetLabel());
if (setting->GetHelp() >= 0)
obj["help"] = g_localizeStrings.Get(setting->GetHelp());
return true;
}
bool CSettingsOperations::SerializeSettingGroup(const CSettingGroup* setting, CVariant &obj)
{
return SerializeISetting(setting, obj);
}
bool CSettingsOperations::SerializeSetting(const CSetting* setting, CVariant &obj)
{
if (!SerializeISetting(setting, obj))
return false;
obj["label"] = g_localizeStrings.Get(setting->GetLabel());
if (setting->GetHelp() >= 0)
obj["help"] = g_localizeStrings.Get(setting->GetHelp());
switch (setting->GetLevel())
{
case SettingLevelBasic:
obj["level"] = "basic";
break;
case SettingLevelStandard:
obj["level"] = "standard";
break;
case SettingLevelAdvanced:
obj["level"] = "advanced";
break;
case SettingLevelExpert:
obj["level"] = "expert";
break;
default:
return false;
}
obj["enabled"] = setting->IsEnabled();
obj["parent"] = setting->GetParent();
obj["control"] = CVariant(CVariant::VariantTypeObject);
if (!SerializeSettingControl(setting->GetControl(), obj["control"]))
return false;
switch (setting->GetType())
{
case SettingTypeBool:
obj["type"] = "boolean";
if (!SerializeSettingBool(static_cast(setting), obj))
return false;
break;
case SettingTypeInteger:
obj["type"] = "integer";
if (!SerializeSettingInt(static_cast(setting), obj))
return false;
break;
case SettingTypeNumber:
obj["type"] = "number";
if (!SerializeSettingNumber(static_cast(setting), obj))
return false;
break;
case SettingTypeString:
obj["type"] = "string";
if (!SerializeSettingString(static_cast(setting), obj))
return false;
break;
case SettingTypeAction:
obj["type"] = "action";
if (!SerializeSettingAction(static_cast(setting), obj))
return false;
break;
case SettingTypeList:
obj["type"] = "list";
if (!SerializeSettingList(static_cast(setting), obj))
return false;
break;
default:
return false;
}
return true;
}
bool CSettingsOperations::SerializeSettingBool(const CSettingBool* setting, CVariant &obj)
{
if (setting == NULL)
return false;
obj["value"] = setting->GetValue();
obj["default"] = setting->GetDefault();
return true;
}
bool CSettingsOperations::SerializeSettingInt(const CSettingInt* setting, CVariant &obj)
{
if (setting == NULL)
return false;
obj["value"] = setting->GetValue();
obj["default"] = setting->GetDefault();
switch (setting->GetOptionsType())
{
case SettingOptionsTypeStatic:
{
obj["options"] = CVariant(CVariant::VariantTypeArray);
const StaticIntegerSettingOptions& options = setting->GetOptions();
for (StaticIntegerSettingOptions::const_iterator itOption = options.begin(); itOption != options.end(); ++itOption)
{
CVariant varOption(CVariant::VariantTypeObject);
varOption["label"] = g_localizeStrings.Get(itOption->first);
varOption["value"] = itOption->second;
obj["options"].push_back(varOption);
}
break;
}
case SettingOptionsTypeDynamic:
{
obj["options"] = CVariant(CVariant::VariantTypeArray);
DynamicIntegerSettingOptions options = const_cast(setting)->UpdateDynamicOptions();
for (DynamicIntegerSettingOptions::const_iterator itOption = options.begin(); itOption != options.end(); ++itOption)
{
CVariant varOption(CVariant::VariantTypeObject);
varOption["label"] = itOption->first;
varOption["value"] = itOption->second;
obj["options"].push_back(varOption);
}
break;
}
case SettingOptionsTypeNone:
default:
obj["minimum"] = setting->GetMinimum();
obj["step"] = setting->GetStep();
obj["maximum"] = setting->GetMaximum();
break;
}
return true;
}
bool CSettingsOperations::SerializeSettingNumber(const CSettingNumber* setting, CVariant &obj)
{
if (setting == NULL)
return false;
obj["value"] = setting->GetValue();
obj["default"] = setting->GetDefault();
obj["minimum"] = setting->GetMinimum();
obj["step"] = setting->GetStep();
obj["maximum"] = setting->GetMaximum();
return true;
}
bool CSettingsOperations::SerializeSettingString(const CSettingString* setting, CVariant &obj)
{
if (setting == NULL)
return false;
obj["value"] = setting->GetValue();
obj["default"] = setting->GetDefault();
obj["allowempty"] = setting->AllowEmpty();
if (setting->GetOptionsType() == SettingOptionsTypeDynamic)
{
obj["options"] = CVariant(CVariant::VariantTypeArray);
DynamicStringSettingOptions options = const_cast(setting)->UpdateDynamicOptions();
for (DynamicStringSettingOptions::const_iterator itOption = options.begin(); itOption != options.end(); ++itOption)
{
CVariant varOption(CVariant::VariantTypeObject);
varOption["label"] = itOption->first;
varOption["value"] = itOption->second;
obj["options"].push_back(varOption);
}
}
const ISettingControl* control = setting->GetControl();
if (control->GetFormat() == "path")
{
if (!SerializeSettingPath(static_cast(setting), obj))
return false;
}
if (control->GetFormat() == "addon")
{
if (!SerializeSettingAddon(static_cast(setting), obj))
return false;
}
return true;
}
bool CSettingsOperations::SerializeSettingAction(const CSettingAction* setting, CVariant &obj)
{
if (setting == NULL)
return false;
return true;
}
bool CSettingsOperations::SerializeSettingList(const CSettingList* setting, CVariant &obj)
{
if (setting == NULL ||
!SerializeSetting(setting->GetDefinition(), obj["definition"]))
return false;
SerializeSettingListValues(CSettingUtils::GetList(setting), obj["value"]);
SerializeSettingListValues(CSettingUtils::ListToValues(setting, setting->GetDefault()), obj["default"]);
obj["elementtype"] = obj["definition"]["type"];
obj["delimiter"] = setting->GetDelimiter();
obj["minimumItems"] = setting->GetMinimumItems();
obj["maximumItems"] = setting->GetMaximumItems();
return true;
}
bool CSettingsOperations::SerializeSettingPath(const CSettingPath* setting, CVariant &obj)
{
if (setting == NULL)
return false;
obj["type"] = "path";
obj["writable"] = setting->Writable();
obj["sources"] = setting->GetSources();
return true;
}
bool CSettingsOperations::SerializeSettingAddon(const CSettingAddon* setting, CVariant &obj)
{
if (setting == NULL)
return false;
obj["type"] = "addon";
obj["addontype"] = ADDON::TranslateType(setting->GetAddonType());
return true;
}
bool CSettingsOperations::SerializeSettingControl(const ISettingControl* control, CVariant &obj)
{
if (control == NULL)
return false;
const std::string& type = control->GetType();
obj["type"] = type;
obj["format"] = control->GetFormat();
obj["delayed"] = control->GetDelayed();
if (type == "spinner")
{
const CSettingControlSpinner* spinner = static_cast(control);
if (spinner == NULL)
return false;
if (spinner->GetFormatLabel() >= 0)
obj["formatlabel"] = g_localizeStrings.Get(spinner->GetFormatLabel());
else if (!spinner->GetFormatString().empty() && spinner->GetFormatString() != "%i")
obj["formatlabel"] = spinner->GetFormatString();
if (spinner->GetMinimumLabel() >= 0)
obj["minimumlabel"] = g_localizeStrings.Get(spinner->GetMinimumLabel());
}
else if (type == "edit")
{
const CSettingControlEdit* edit = static_cast(control);
if (edit == NULL)
return false;
obj["hidden"] = edit->IsHidden();
obj["verifynewvalue"] = edit->VerifyNewValue();
if (edit->GetHeading() >= 0)
obj["heading"] = g_localizeStrings.Get(edit->GetHeading());
}
else if (type == "button")
{
const CSettingControlButton* button = static_cast(control);
if (button == NULL)
return false;
if (button->GetHeading() >= 0)
obj["heading"] = g_localizeStrings.Get(button->GetHeading());
}
else if (type == "list")
{
const CSettingControlList* list = static_cast(control);
if (list == NULL)
return false;
if (list->GetHeading() >= 0)
obj["heading"] = g_localizeStrings.Get(list->GetHeading());
obj["multiselect"] = list->CanMultiSelect();
}
else if (type == "slider")
{
const CSettingControlSlider* slider = static_cast(control);
if (slider == NULL)
return false;
if (slider->GetHeading() >= 0)
obj["heading"] = g_localizeStrings.Get(slider->GetHeading());
obj["popup"] = slider->UsePopup();
if (slider->GetFormatLabel() >= 0)
obj["formatlabel"] = g_localizeStrings.Get(slider->GetFormatLabel());
else
obj["formatlabel"] = slider->GetFormatString();
}
else if (type == "range")
{
const CSettingControlRange* range = static_cast(control);
if (range == NULL)
return false;
if (range->GetFormatLabel() >= 0)
obj["formatlabel"] = g_localizeStrings.Get(range->GetFormatLabel());
else
obj["formatlabel"] = "";
if (range->GetValueFormatLabel() >= 0)
obj["formatvalue"] = g_localizeStrings.Get(range->GetValueFormatLabel());
else
obj["formatvalue"] = range->GetValueFormat();
}
else if (type != "toggle")
return false;
return true;
}
void CSettingsOperations::SerializeSettingListValues(const std::vector &values, CVariant &obj)
{
obj = CVariant(CVariant::VariantTypeArray);
for (std::vector::const_iterator itValue = values.begin(); itValue != values.end(); ++itValue)
obj.push_back(*itValue);
}