Merge pull request #24470 from fuzzard/release_20.3
[xbmc.git] / xbmc / settings / SettingControl.cpp
blob3c73b8997c58e95a44460b6749dced2f5f5a12eb
1 /*
2 * Copyright (C) 2013-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "SettingControl.h"
11 #include "settings/lib/SettingDefinitions.h"
12 #include "utils/StringUtils.h"
13 #include "utils/XBMCTinyXML.h"
14 #include "utils/XMLUtils.h"
15 #include "utils/log.h"
17 #include <vector>
19 const char* SHOW_ADDONS_ALL = "all";
20 const char* SHOW_ADDONS_INSTALLED = "installed";
21 const char* SHOW_ADDONS_INSTALLABLE = "installable";
23 std::shared_ptr<ISettingControl> CSettingControlCreator::CreateControl(const std::string &controlType) const
25 if (StringUtils::EqualsNoCase(controlType, "toggle"))
26 return std::make_shared<CSettingControlCheckmark>();
27 else if (StringUtils::EqualsNoCase(controlType, "spinner"))
28 return std::make_shared<CSettingControlSpinner>();
29 else if (StringUtils::EqualsNoCase(controlType, "edit"))
30 return std::make_shared<CSettingControlEdit>();
31 else if (StringUtils::EqualsNoCase(controlType, "button"))
32 return std::make_shared<CSettingControlButton>();
33 else if (StringUtils::EqualsNoCase(controlType, "list"))
34 return std::make_shared<CSettingControlList>();
35 else if (StringUtils::EqualsNoCase(controlType, "slider"))
36 return std::make_shared<CSettingControlSlider>();
37 else if (StringUtils::EqualsNoCase(controlType, "range"))
38 return std::make_shared<CSettingControlRange>();
39 else if (StringUtils::EqualsNoCase(controlType, "title"))
40 return std::make_shared<CSettingControlTitle>();
41 else if (StringUtils::EqualsNoCase(controlType, "label"))
42 return std::make_shared<CSettingControlLabel>();
43 else if (StringUtils::EqualsNoCase(controlType, "colorbutton"))
44 return std::make_shared<CSettingControlColorButton>();
46 return nullptr;
49 bool CSettingControlCheckmark::SetFormat(const std::string &format)
51 return format.empty() || StringUtils::EqualsNoCase(format, "boolean");
54 bool CSettingControlFormattedRange::Deserialize(const TiXmlNode *node, bool update /* = false */)
56 if (!ISettingControl::Deserialize(node, update))
57 return false;
59 if (m_format == "string")
61 XMLUtils::GetInt(node, SETTING_XML_ELM_CONTROL_FORMATLABEL, m_formatLabel);
63 // get the minimum label from <setting><constraints><minimum label="X" />
64 auto settingNode = node->Parent();
65 if (settingNode != nullptr)
67 auto constraintsNode = settingNode->FirstChild(SETTING_XML_ELM_CONSTRAINTS);
68 if (constraintsNode != nullptr)
70 auto minimumNode = constraintsNode->FirstChild(SETTING_XML_ELM_MINIMUM);
71 if (minimumNode != nullptr)
73 auto minimumElem = minimumNode->ToElement();
74 if (minimumElem != nullptr)
76 if (minimumElem->QueryIntAttribute(SETTING_XML_ATTR_LABEL, &m_minimumLabel) != TIXML_SUCCESS)
77 m_minimumLabel = -1;
83 if (m_minimumLabel < 0)
85 std::string strFormat;
86 if (XMLUtils::GetString(node, SETTING_XML_ATTR_FORMAT, strFormat) && !strFormat.empty())
87 m_formatString = strFormat;
91 return true;
94 bool CSettingControlSpinner::SetFormat(const std::string &format)
96 if (!StringUtils::EqualsNoCase(format, "string") &&
97 !StringUtils::EqualsNoCase(format, "integer") &&
98 !StringUtils::EqualsNoCase(format, "number"))
99 return false;
101 m_format = format;
102 StringUtils::ToLower(m_format);
104 return true;
107 bool CSettingControlEdit::Deserialize(const TiXmlNode *node, bool update /* = false */)
109 if (!ISettingControl::Deserialize(node, update))
110 return false;
112 XMLUtils::GetBoolean(node, SETTING_XML_ELM_CONTROL_HIDDEN, m_hidden);
113 XMLUtils::GetBoolean(node, SETTING_XML_ELM_CONTROL_VERIFYNEW, m_verifyNewValue);
114 XMLUtils::GetInt(node, SETTING_XML_ELM_CONTROL_HEADING, m_heading);
116 return true;
119 bool CSettingControlEdit::SetFormat(const std::string &format)
121 if (!StringUtils::EqualsNoCase(format, "string") &&
122 !StringUtils::EqualsNoCase(format, "integer") &&
123 !StringUtils::EqualsNoCase(format, "number") &&
124 !StringUtils::EqualsNoCase(format, "ip") &&
125 !StringUtils::EqualsNoCase(format, "md5") &&
126 !StringUtils::EqualsNoCase(format, "urlencoded"))
127 return false;
129 m_format = format;
130 StringUtils::ToLower(m_format);
132 return true;
135 bool CSettingControlButton::Deserialize(const TiXmlNode *node, bool update /* = false */)
137 if (!ISettingControl::Deserialize(node, update))
138 return false;
140 XMLUtils::GetInt(node, SETTING_XML_ELM_CONTROL_HEADING, m_heading);
141 XMLUtils::GetBoolean(node, SETTING_XML_ELM_CONTROL_HIDEVALUE, m_hideValue);
143 if (m_format == "action")
145 bool closeDialog = false;
146 if (XMLUtils::GetBoolean(node, "close", closeDialog))
147 m_closeDialog = closeDialog;
148 std::string strActionData;
149 if (XMLUtils::GetString(node, SETTING_XML_ELM_DATA, strActionData))
150 m_actionData = strActionData;
152 else if (m_format == "addon")
154 std::string strShowAddons;
155 if (XMLUtils::GetString(node, "show", strShowAddons) && !strShowAddons.empty())
157 if (StringUtils::EqualsNoCase(strShowAddons, SHOW_ADDONS_ALL))
159 m_showInstalledAddons = true;
160 m_showInstallableAddons = true;
162 else if (StringUtils::EqualsNoCase(strShowAddons, SHOW_ADDONS_INSTALLED))
164 m_showInstalledAddons = true;
165 m_showInstallableAddons = false;
167 else if (StringUtils::EqualsNoCase(strShowAddons, SHOW_ADDONS_INSTALLABLE))
169 m_showInstalledAddons = false;
170 m_showInstallableAddons = true;
172 else
173 CLog::Log(LOGWARNING, "CSettingControlButton: invalid <show>");
175 auto show = node->FirstChildElement("show");
176 if (show != nullptr)
178 const char *strShowDetails = nullptr;
179 if ((strShowDetails = show->Attribute(SETTING_XML_ATTR_SHOW_DETAILS)) != nullptr)
181 if (StringUtils::EqualsNoCase(strShowDetails, "false") || StringUtils::EqualsNoCase(strShowDetails, "true"))
182 m_showAddonDetails = StringUtils::EqualsNoCase(strShowDetails, "true");
183 else
184 CLog::Log(LOGWARNING, "CSettingControlButton: error reading \"details\" attribute of <show>");
187 if (!m_showInstallableAddons)
189 const char *strShowMore = nullptr;
190 if ((strShowMore = show->Attribute(SETTING_XML_ATTR_SHOW_MORE)) != nullptr)
192 if (StringUtils::EqualsNoCase(strShowMore, "false") || StringUtils::EqualsNoCase(strShowMore, "true"))
193 m_showMoreAddons = StringUtils::EqualsNoCase(strShowMore, "true");
194 else
195 CLog::Log(LOGWARNING, "CSettingControlButton: error reading \"more\" attribute of <show>");
201 else if (m_format == "file")
203 bool useThumbs = false;
204 if (XMLUtils::GetBoolean(node, "usethumbs", useThumbs))
205 m_useImageThumbs = useThumbs;
206 bool useFileDirectories = false;
207 if (XMLUtils::GetBoolean(node, "treatasfolder", useFileDirectories))
208 m_useFileDirectories = useFileDirectories;
211 return true;
214 bool CSettingControlButton::SetFormat(const std::string &format)
216 if (!StringUtils::EqualsNoCase(format, "path") &&
217 !StringUtils::EqualsNoCase(format, "file") &&
218 !StringUtils::EqualsNoCase(format, "image") &&
219 !StringUtils::EqualsNoCase(format, "addon") &&
220 !StringUtils::EqualsNoCase(format, "action") &&
221 !StringUtils::EqualsNoCase(format, "infolabel") &&
222 !StringUtils::EqualsNoCase(format, "date") &&
223 !StringUtils::EqualsNoCase(format, "time"))
224 return false;
226 m_format = format;
227 StringUtils::ToLower(m_format);
229 return true;
232 bool CSettingControlList::Deserialize(const TiXmlNode *node, bool update /* = false */)
234 if (!CSettingControlFormattedRange::Deserialize(node, update))
235 return false;
237 XMLUtils::GetInt(node, SETTING_XML_ELM_CONTROL_HEADING, m_heading);
238 XMLUtils::GetBoolean(node, SETTING_XML_ELM_CONTROL_MULTISELECT, m_multiselect);
239 XMLUtils::GetBoolean(node, SETTING_XML_ELM_CONTROL_HIDEVALUE, m_hideValue);
240 XMLUtils::GetInt(node, SETTING_XML_ELM_CONTROL_ADDBUTTONLABEL, m_addButtonLabel);
242 return true;
245 bool CSettingControlList::SetFormat(const std::string &format)
247 if (!StringUtils::EqualsNoCase(format, "string") &&
248 !StringUtils::EqualsNoCase(format, "integer"))
249 return false;
251 m_format = format;
252 StringUtils::ToLower(m_format);
254 return true;
257 bool CSettingControlSlider::Deserialize(const TiXmlNode *node, bool update /* = false */)
259 if (!ISettingControl::Deserialize(node, update))
260 return false;
262 XMLUtils::GetInt(node, SETTING_XML_ELM_CONTROL_HEADING, m_heading);
263 XMLUtils::GetBoolean(node, SETTING_XML_ELM_CONTROL_POPUP, m_popup);
265 XMLUtils::GetInt(node, SETTING_XML_ELM_CONTROL_FORMATLABEL, m_formatLabel);
266 if (m_formatLabel < 0)
268 std::string strFormat;
269 if (XMLUtils::GetString(node, SETTING_XML_ATTR_FORMAT, strFormat) && !strFormat.empty())
270 m_formatString = strFormat;
273 return true;
276 bool CSettingControlSlider::SetFormat(const std::string &format)
278 if (!StringUtils::EqualsNoCase(format, "percentage") &&
279 !StringUtils::EqualsNoCase(format, "integer") &&
280 !StringUtils::EqualsNoCase(format, "number"))
281 return false;
283 m_format = format;
284 StringUtils::ToLower(m_format);
285 m_formatString = GetDefaultFormatString();
287 return true;
290 std::string CSettingControlSlider::GetDefaultFormatString() const
292 if (m_format == "percentage")
293 return "{} %";
294 if (m_format == "integer")
295 return "{:d}";
296 if (m_format == "number")
297 return "{:.1f}";
299 return "{}";
302 bool CSettingControlRange::Deserialize(const TiXmlNode *node, bool update /* = false */)
304 if (!ISettingControl::Deserialize(node, update))
305 return false;
307 auto formatLabel = node->FirstChildElement(SETTING_XML_ELM_CONTROL_FORMATLABEL);
308 if (formatLabel != nullptr)
310 XMLUtils::GetInt(node, SETTING_XML_ELM_CONTROL_FORMATLABEL, m_formatLabel);
311 if (m_formatLabel < 0)
312 return false;
314 auto formatValue = formatLabel->Attribute(SETTING_XML_ELM_CONTROL_FORMATVALUE);
315 if (formatValue != nullptr)
317 if (StringUtils::IsInteger(formatValue))
318 m_valueFormatLabel = (int)strtol(formatValue, nullptr, 0);
319 else
321 m_valueFormat = formatValue;
322 if (!m_valueFormat.empty())
323 m_valueFormatLabel = -1;
328 return true;
331 bool CSettingControlRange::SetFormat(const std::string &format)
333 if (StringUtils::EqualsNoCase(format, "percentage"))
334 m_valueFormat = "{} %";
335 else if (StringUtils::EqualsNoCase(format, "integer"))
336 m_valueFormat = "{:d}";
337 else if (StringUtils::EqualsNoCase(format, "number"))
338 m_valueFormat = "{:.1f}";
339 else if (StringUtils::EqualsNoCase(format, "date") ||
340 StringUtils::EqualsNoCase(format, "time"))
341 m_valueFormat.clear();
342 else
343 return false;
345 m_format = format;
346 StringUtils::ToLower(m_format);
348 return true;
351 bool CSettingControlTitle::Deserialize(const TiXmlNode *node, bool update /* = false */)
353 if (!ISettingControl::Deserialize(node, update))
354 return false;
356 std::string strTmp;
357 if (XMLUtils::GetString(node, SETTING_XML_ATTR_SEPARATOR_POSITION, strTmp))
359 if (!StringUtils::EqualsNoCase(strTmp, "top") && !StringUtils::EqualsNoCase(strTmp, "bottom"))
360 CLog::Log(LOGWARNING, "CSettingControlTitle: error reading \"value\" attribute of <{}>",
361 SETTING_XML_ATTR_SEPARATOR_POSITION);
362 else
363 m_separatorBelowLabel = StringUtils::EqualsNoCase(strTmp, "bottom");
365 XMLUtils::GetBoolean(node, SETTING_XML_ATTR_HIDE_SEPARATOR, m_separatorHidden);
367 return true;
370 CSettingControlLabel::CSettingControlLabel()
372 m_format = "string";
375 bool CSettingControlColorButton::SetFormat(const std::string& format)
377 return format.empty() || StringUtils::EqualsNoCase(format, "string");