summaryrefslogtreecommitdiffstats
path: root/xbmc/addons/GUIDialogAddonSettings.cpp
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2015-03-03 16:53:59 +0100
committermanuel <manuel@mausz.at>2015-03-03 16:53:59 +0100
commitffca21f2743a7b367fa212799c6e2fea6190dd5d (patch)
tree0608ea3a29cf644ec9ab204e2b4bb9bfaae1c381 /xbmc/addons/GUIDialogAddonSettings.cpp
downloadkodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.tar.gz
kodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.tar.bz2
kodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.zip
initial commit for kodi master
Diffstat (limited to 'xbmc/addons/GUIDialogAddonSettings.cpp')
-rw-r--r--xbmc/addons/GUIDialogAddonSettings.cpp1200
1 files changed, 1200 insertions, 0 deletions
diff --git a/xbmc/addons/GUIDialogAddonSettings.cpp b/xbmc/addons/GUIDialogAddonSettings.cpp
new file mode 100644
index 0000000..ef1c3c2
--- /dev/null
+++ b/xbmc/addons/GUIDialogAddonSettings.cpp
@@ -0,0 +1,1200 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "GUIDialogAddonSettings.h"
22#include "filesystem/PluginDirectory.h"
23#include "addons/IAddon.h"
24#include "addons/AddonManager.h"
25#include "dialogs/GUIDialogNumeric.h"
26#include "dialogs/GUIDialogFileBrowser.h"
27#include "dialogs/GUIDialogOK.h"
28#include "guilib/GUIControlGroupList.h"
29#include "guilib/GUISettingsSliderControl.h"
30#include "utils/URIUtils.h"
31#include "utils/StringUtils.h"
32#include "storage/MediaManager.h"
33#include "guilib/GUILabelControl.h"
34#include "guilib/GUIRadioButtonControl.h"
35#include "guilib/GUISpinControlEx.h"
36#include "guilib/GUIImage.h"
37#include "input/Key.h"
38#include "filesystem/Directory.h"
39#include "video/VideoInfoScanner.h"
40#include "addons/Scraper.h"
41#include "guilib/GUIWindowManager.h"
42#include "ApplicationMessenger.h"
43#include "guilib/GUIKeyboardFactory.h"
44#include "FileItem.h"
45#include "settings/AdvancedSettings.h"
46#include "settings/MediaSourceSettings.h"
47#include "GUIInfoManager.h"
48#include "GUIUserMessages.h"
49#include "dialogs/GUIDialogSelect.h"
50#include "GUIWindowAddonBrowser.h"
51#include "utils/log.h"
52#include "Util.h"
53#include "URL.h"
54#include "utils/XMLUtils.h"
55
56using namespace std;
57using namespace ADDON;
58using XFILE::CDirectory;
59
60#define CONTROL_SETTINGS_AREA 2
61#define CONTROL_DEFAULT_BUTTON 3
62#define CONTROL_DEFAULT_RADIOBUTTON 4
63#define CONTROL_DEFAULT_SPIN 5
64#define CONTROL_DEFAULT_SEPARATOR 6
65#define CONTROL_DEFAULT_LABEL_SEPARATOR 7
66#define CONTROL_DEFAULT_SLIDER 8
67#define CONTROL_SECTION_AREA 9
68#define CONTROL_DEFAULT_SECTION_BUTTON 13
69
70#define ID_BUTTON_OK 10
71#define ID_BUTTON_CANCEL 11
72#define ID_BUTTON_DEFAULT 12
73#define CONTROL_HEADING_LABEL 20
74
75#define CONTROL_START_SECTION 100
76#define CONTROL_START_SETTING 200
77
78CGUIDialogAddonSettings::CGUIDialogAddonSettings()
79 : CGUIDialogBoxBase(WINDOW_DIALOG_ADDON_SETTINGS, "DialogAddonSettings.xml")
80{
81 m_currentSection = 0;
82 m_totalSections = 1;
83 m_saveToDisk = false;
84}
85
86CGUIDialogAddonSettings::~CGUIDialogAddonSettings(void)
87{
88}
89
90bool CGUIDialogAddonSettings::OnMessage(CGUIMessage& message)
91{
92 switch (message.GetMessage())
93 {
94 case GUI_MSG_WINDOW_DEINIT:
95 {
96 FreeSections();
97 }
98 break;
99 case GUI_MSG_CLICKED:
100 {
101 int iControl = message.GetSenderId();
102 bool bCloseDialog = false;
103
104 if (iControl == ID_BUTTON_DEFAULT)
105 SetDefaultSettings();
106 else if (iControl != ID_BUTTON_OK)
107 bCloseDialog = ShowVirtualKeyboard(iControl);
108
109 if (iControl == ID_BUTTON_OK || iControl == ID_BUTTON_CANCEL || bCloseDialog)
110 {
111 if (iControl == ID_BUTTON_OK || bCloseDialog)
112 {
113 m_bConfirmed = true;
114 SaveSettings();
115 }
116 Close();
117 return true;
118 }
119 }
120 break;
121 case GUI_MSG_FOCUSED:
122 {
123 CGUIDialogBoxBase::OnMessage(message);
124 int focusedControl = GetFocusedControlID();
125 if (focusedControl >= CONTROL_START_SECTION && focusedControl < (int)(CONTROL_START_SECTION + m_totalSections) &&
126 focusedControl - CONTROL_START_SECTION != (int)m_currentSection)
127 { // changing section
128 UpdateFromControls();
129 m_currentSection = focusedControl - CONTROL_START_SECTION;
130 CreateControls();
131 }
132 return true;
133 }
134 case GUI_MSG_SETTING_UPDATED:
135 {
136 std::string id = message.GetStringParam(0);
137 std::string value = message.GetStringParam(1);
138 m_settings[id] = value;
139 if (GetFocusedControl())
140 {
141 int iControl = GetFocusedControl()->GetID();
142 CreateControls();
143 CGUIMessage msg(GUI_MSG_SETFOCUS,GetID(),iControl);
144 OnMessage(msg);
145 }
146 return true;
147 }
148 }
149 return CGUIDialogBoxBase::OnMessage(message);
150}
151
152bool CGUIDialogAddonSettings::OnAction(const CAction& action)
153{
154 if (action.GetID() == ACTION_DELETE_ITEM)
155 {
156 CGUIControl* pControl = GetFocusedControl();
157 if (pControl)
158 {
159 int iControl = pControl->GetID();
160 int controlId = CONTROL_START_SETTING;
161 const TiXmlElement* setting = GetFirstSetting();
162 UpdateFromControls();
163 while (setting)
164 {
165 if (controlId == iControl)
166 {
167 const char* id = setting->Attribute("id");
168 const char* value = setting->Attribute("default");
169 if (id && value)
170 m_settings[id] = value;
171 CreateControls();
172 CGUIMessage msg(GUI_MSG_SETFOCUS,GetID(),iControl);
173 OnMessage(msg);
174 return true;
175 }
176 setting = setting->NextSiblingElement("setting");
177 controlId++;
178 }
179 }
180 }
181 return CGUIDialogBoxBase::OnAction(action);
182}
183
184void CGUIDialogAddonSettings::OnInitWindow()
185{
186 m_currentSection = 0;
187 m_totalSections = 1;
188 CreateSections();
189 CreateControls();
190 CGUIDialogBoxBase::OnInitWindow();
191}
192
193// \brief Show CGUIDialogOK dialog, then wait for user to dismiss it.
194bool CGUIDialogAddonSettings::ShowAndGetInput(const AddonPtr &addon, bool saveToDisk /* = true */)
195{
196 if (!addon)
197 return false;
198
199 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
200 return false;
201
202 bool ret(false);
203 if (addon->HasSettings())
204 {
205 // Create the dialog
206 CGUIDialogAddonSettings* pDialog = NULL;
207 pDialog = (CGUIDialogAddonSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_ADDON_SETTINGS);
208 if (!pDialog)
209 return false;
210
211 // Set the heading
212 std::string heading = StringUtils::Format("$LOCALIZE[10004] - %s", addon->Name().c_str()); // "Settings - AddonName"
213 pDialog->m_strHeading = heading;
214
215 pDialog->m_addon = addon;
216 pDialog->m_saveToDisk = saveToDisk;
217 pDialog->DoModal();
218 ret = true;
219 }
220 else
221 { // addon does not support settings, inform user
222 CGUIDialogOK::ShowAndGetInput(24000,0,24030,0);
223 }
224
225 return ret;
226}
227
228bool CGUIDialogAddonSettings::ShowVirtualKeyboard(int iControl)
229{
230 int controlId = CONTROL_START_SETTING;
231 bool bCloseDialog = false;
232
233 const TiXmlElement *setting = GetFirstSetting();
234 while (setting)
235 {
236 if (controlId == iControl)
237 {
238 const CGUIControl* control = GetControl(controlId);
239 const std::string id = XMLUtils::GetAttribute(setting, "id");
240 const std::string type = XMLUtils::GetAttribute(setting, "type");
241
242 //Special handling for actions: does not require id attribute. TODO: refactor me.
243 if (control && control->GetControlType() == CGUIControl::GUICONTROL_BUTTON && type == "action")
244 {
245 const char *option = setting->Attribute("option");
246 std::string action = XMLUtils::GetAttribute(setting, "action");
247 if (!action.empty())
248 {
249 // replace $CWD with the url of plugin/script
250 StringUtils::Replace(action, "$CWD", m_addon->Path());
251 StringUtils::Replace(action, "$ID", m_addon->ID());
252 if (option)
253 bCloseDialog = (strcmpi(option, "close") == 0);
254 CApplicationMessenger::Get().ExecBuiltIn(action);
255 }
256 break;
257 }
258
259 if (control && control->GetControlType() == CGUIControl::GUICONTROL_BUTTON &&
260 !id.empty() && !type.empty())
261 {
262 const char *option = setting->Attribute("option");
263 const char *source = setting->Attribute("source");
264 std::string value = m_buttonValues[id];
265 std::string label = GetString(setting->Attribute("label"));
266
267 if (type == "text")
268 {
269 // get any options
270 bool bHidden = false;
271 bool bEncoded = false;
272 if (option)
273 {
274 bHidden = (strstr(option, "hidden") != NULL);
275 bEncoded = (strstr(option, "urlencoded") != NULL);
276 }
277 if (bEncoded)
278 value = CURL::Decode(value);
279
280 if (CGUIKeyboardFactory::ShowAndGetInput(value, label, true, bHidden))
281 {
282 // if hidden hide input
283 if (bHidden)
284 {
285 std::string hiddenText;
286 hiddenText.append(value.size(), L'*');
287 ((CGUIButtonControl *)control)->SetLabel2(hiddenText);
288 }
289 else
290 ((CGUIButtonControl*) control)->SetLabel2(value);
291 if (bEncoded)
292 value = CURL::Encode(value);
293 }
294 }
295 else if (type == "number" && CGUIDialogNumeric::ShowAndGetNumber(value, label))
296 {
297 ((CGUIButtonControl*) control)->SetLabel2(value);
298 }
299 else if (type == "ipaddress" && CGUIDialogNumeric::ShowAndGetIPAddress(value, label))
300 {
301 ((CGUIButtonControl*) control)->SetLabel2(value);
302 }
303 else if (type == "select")
304 {
305 CGUIDialogSelect *pDlg = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
306 if (pDlg)
307 {
308 pDlg->SetHeading(label.c_str());
309 pDlg->Reset();
310
311 int selected = -1;
312 vector<std::string> valuesVec;
313 if (setting->Attribute("values"))
314 StringUtils::Tokenize(setting->Attribute("values"), valuesVec, "|");
315 else if (setting->Attribute("lvalues"))
316 { // localize
317 StringUtils::Tokenize(setting->Attribute("lvalues"), valuesVec, "|");
318 for (unsigned int i = 0; i < valuesVec.size(); i++)
319 {
320 if (i == (unsigned int)atoi(value.c_str()))
321 selected = i;
322 std::string localized = m_addon->GetString(atoi(valuesVec[i].c_str()));
323 if (localized.empty())
324 localized = g_localizeStrings.Get(atoi(valuesVec[i].c_str()));
325 valuesVec[i] = localized;
326 }
327 }
328 else if (source)
329 {
330 valuesVec = GetFileEnumValues(source, XMLUtils::GetAttribute(setting, "mask"), XMLUtils::GetAttribute(setting, "option"));
331 }
332
333 for (unsigned int i = 0; i < valuesVec.size(); i++)
334 {
335 pDlg->Add(valuesVec[i]);
336 if (selected == (int)i || (selected < 0 && StringUtils::EqualsNoCase(valuesVec[i], value)))
337 pDlg->SetSelected(i); // FIXME: the SetSelected() does not select "i", it always defaults to the first position
338 }
339 pDlg->DoModal();
340 int iSelected = pDlg->GetSelectedLabel();
341 if (iSelected >= 0)
342 {
343 if (setting->Attribute("lvalues"))
344 value = StringUtils::Format("%i", iSelected);
345 else
346 value = valuesVec[iSelected];
347 ((CGUIButtonControl*) control)->SetLabel2(valuesVec[iSelected]);
348 }
349 }
350 }
351 else if (type == "audio" || type == "video"
352 || type == "image" || type == "executable"
353 || type == "file" || type == "folder")
354 {
355 // setup the shares
356 VECSOURCES *shares = NULL;
357 if (source && strcmpi(source, "") != 0)
358 shares = CMediaSourceSettings::Get().GetSources(source);
359
360 VECSOURCES localShares;
361 if (!shares)
362 {
363 g_mediaManager.GetLocalDrives(localShares);
364 if (!source || strcmpi(source, "local") != 0)
365 g_mediaManager.GetNetworkLocations(localShares);
366 }
367 else // always append local drives
368 {
369 localShares = *shares;
370 g_mediaManager.GetLocalDrives(localShares);
371 }
372
373 if (type == "folder")
374 {
375 // get any options
376 bool bWriteOnly = false;
377 if (option)
378 bWriteOnly = (strcmpi(option, "writeable") == 0);
379
380 if (CGUIDialogFileBrowser::ShowAndGetDirectory(localShares, label, value, bWriteOnly))
381 ((CGUIButtonControl*) control)->SetLabel2(value);
382 }
383 else if (type == "image")
384 {
385 if (CGUIDialogFileBrowser::ShowAndGetImage(localShares, label, value))
386 ((CGUIButtonControl*) control)->SetLabel2(value);
387 }
388 else
389 {
390 // set the proper mask
391 std::string strMask;
392 if (setting->Attribute("mask"))
393 {
394 strMask = setting->Attribute("mask");
395 // convert mask qualifiers
396 StringUtils::Replace(strMask, "$AUDIO", g_advancedSettings.m_musicExtensions);
397 StringUtils::Replace(strMask, "$VIDEO", g_advancedSettings.m_videoExtensions);
398 StringUtils::Replace(strMask, "$IMAGE", g_advancedSettings.m_pictureExtensions);
399#if defined(_WIN32_WINNT)
400 StringUtils::Replace(strMask, "$EXECUTABLE", ".exe|.bat|.cmd|.py");
401#else
402 StringUtils::Replace(strMask, "$EXECUTABLE", "");
403#endif
404 }
405 else
406 {
407 if (type == "video")
408 strMask = g_advancedSettings.m_videoExtensions;
409 else if (type == "audio")
410 strMask = g_advancedSettings.m_musicExtensions;
411 else if (type == "executable")
412#if defined(_WIN32_WINNT)
413 strMask = ".exe|.bat|.cmd|.py";
414#else
415 strMask = "";
416#endif
417 }
418
419 // get any options
420 bool bUseThumbs = false;
421 bool bUseFileDirectories = false;
422 if (option)
423 {
424 vector<string> options = StringUtils::Split(option, '|');
425 bUseThumbs = find(options.begin(), options.end(), "usethumbs") != options.end();
426 bUseFileDirectories = find(options.begin(), options.end(), "treatasfolder") != options.end();
427 }
428
429 if (CGUIDialogFileBrowser::ShowAndGetFile(localShares, strMask, label, value, bUseThumbs, bUseFileDirectories))
430 ((CGUIButtonControl*) control)->SetLabel2(value);
431 }
432 }
433 else if (type == "date")
434 {
435 CDateTime date;
436 if (!value.empty())
437 date.SetFromDBDate(value);
438 SYSTEMTIME timedate;
439 date.GetAsSystemTime(timedate);
440 if(CGUIDialogNumeric::ShowAndGetDate(timedate, label))
441 {
442 date = timedate;
443 value = date.GetAsDBDate();
444 ((CGUIButtonControl*) control)->SetLabel2(value);
445 }
446 }
447 else if (type == "time")
448 {
449 SYSTEMTIME timedate;
450 if (value.size() >= 5)
451 {
452 // assumes HH:MM
453 timedate.wHour = atoi(value.substr(0, 2).c_str());
454 timedate.wMinute = atoi(value.substr(3, 2).c_str());
455 }
456 if (CGUIDialogNumeric::ShowAndGetTime(timedate, label))
457 {
458 value = StringUtils::Format("%02d:%02d", timedate.wHour, timedate.wMinute);
459 ((CGUIButtonControl*) control)->SetLabel2(value);
460 }
461 }
462 else if (type == "addon")
463 {
464 const char *strType = setting->Attribute("addontype");
465 if (strType)
466 {
467 vector<string> addonTypes = StringUtils::Split(strType, ',');
468 vector<ADDON::TYPE> types;
469 for (vector<string>::iterator i = addonTypes.begin(); i != addonTypes.end(); ++i)
470 {
471 StringUtils::Trim(*i);
472 ADDON::TYPE type = TranslateType(*i);
473 if (type != ADDON_UNKNOWN)
474 types.push_back(type);
475 }
476 if (types.size() > 0)
477 {
478 const char *strMultiselect = setting->Attribute("multiselect");
479 bool multiSelect = strMultiselect && strcmpi(strMultiselect, "true") == 0;
480 if (multiSelect)
481 {
482 // construct vector of addon IDs (IDs are comma seperated in single string)
483 vector<string> addonIDs = StringUtils::Split(value, ',');
484 if (CGUIWindowAddonBrowser::SelectAddonID(types, addonIDs, false) == 1)
485 {
486 value = StringUtils::Join(addonIDs, ",");
487 ((CGUIButtonControl*) control)->SetLabel2(GetAddonNames(value));
488 }
489 }
490 else // no need of string splitting/joining if we select only 1 addon
491 if (CGUIWindowAddonBrowser::SelectAddonID(types, value, false) == 1)
492 ((CGUIButtonControl*) control)->SetLabel2(GetAddonNames(value));
493 }
494 }
495 }
496 m_buttonValues[id] = value;
497 break;
498 }
499 }
500 setting = setting->NextSiblingElement("setting");
501 controlId++;
502 }
503 EnableControls();
504 return bCloseDialog;
505}
506
507void CGUIDialogAddonSettings::UpdateFromControls()
508{
509 int controlID = CONTROL_START_SETTING;
510 const TiXmlElement *setting = GetFirstSetting();
511 while (setting)
512 {
513 const std::string id = XMLUtils::GetAttribute(setting, "id");
514 const std::string type = XMLUtils::GetAttribute(setting, "type");
515 const CGUIControl* control = GetControl(controlID++);
516
517 if (control)
518 {
519 std::string value;
520 switch (control->GetControlType())
521 {
522 case CGUIControl::GUICONTROL_BUTTON:
523 value = m_buttonValues[id];
524 break;
525 case CGUIControl::GUICONTROL_RADIO:
526 value = ((CGUIRadioButtonControl*) control)->IsSelected() ? "true" : "false";
527 break;
528 case CGUIControl::GUICONTROL_SPINEX:
529 if (type == "fileenum" || type == "labelenum")
530 value = ((CGUISpinControlEx*) control)->GetLabel();
531 else
532 value = StringUtils::Format("%i", ((CGUISpinControlEx*) control)->GetValue());
533 break;
534 case CGUIControl::GUICONTROL_SETTINGS_SLIDER:
535 {
536 std::string option = XMLUtils::GetAttribute(setting, "option");
537 if (option.size() == 0 || StringUtils::EqualsNoCase(option, "float"))
538 value = StringUtils::Format("%f", ((CGUISettingsSliderControl *)control)->GetFloatValue());
539 else
540 value = StringUtils::Format("%i", ((CGUISettingsSliderControl *)control)->GetIntValue());
541 }
542 break;
543 default:
544 break;
545 }
546 m_settings[id] = value;
547 }
548
549 setting = setting->NextSiblingElement("setting");
550 }
551}
552
553void CGUIDialogAddonSettings::SaveSettings(void)
554{
555 UpdateFromControls();
556
557 for (map<std::string, std::string>::iterator i = m_settings.begin(); i != m_settings.end(); ++i)
558 m_addon->UpdateSetting(i->first, i->second);
559
560 if (m_saveToDisk)
561 {
562 m_addon->SaveSettings();
563 }
564}
565
566void CGUIDialogAddonSettings::FreeSections()
567{
568 CGUIControlGroupList *group = dynamic_cast<CGUIControlGroupList *>(GetControl(CONTROL_SECTION_AREA));
569 if (group)
570 {
571 group->FreeResources();
572 group->ClearAll();
573 }
574 m_settings.clear();
575 m_buttonValues.clear();
576 FreeControls();
577}
578
579void CGUIDialogAddonSettings::FreeControls()
580{
581 // clear the category group
582 CGUIControlGroupList *control = dynamic_cast<CGUIControlGroupList *>(GetControl(CONTROL_SETTINGS_AREA));
583 if (control)
584 {
585 control->FreeResources();
586 control->ClearAll();
587 }
588}
589
590void CGUIDialogAddonSettings::CreateSections()
591{
592 CGUIControlGroupList *group = dynamic_cast<CGUIControlGroupList *>(GetControl(CONTROL_SECTION_AREA));
593 CGUIButtonControl *originalButton = dynamic_cast<CGUIButtonControl *>(GetControl(CONTROL_DEFAULT_SECTION_BUTTON));
594 if (!m_addon)
595 return;
596
597 if (originalButton)
598 originalButton->SetVisible(false);
599
600 // clear the category group
601 FreeSections();
602
603 // grab our categories
604 const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category");
605 if (!category) // add a default one...
606 category = m_addon->GetSettingsXML();
607
608 int buttonID = CONTROL_START_SECTION;
609 while (category)
610 { // add a category
611 CGUIButtonControl *button = originalButton ? originalButton->Clone() : NULL;
612
613 std::string label = GetString(category->Attribute("label"));
614 if (label.empty())
615 label = g_localizeStrings.Get(128);
616
617 if (buttonID >= CONTROL_START_SETTING)
618 {
619 CLog::Log(LOGERROR, "%s - cannot have more than %d categories - simplify your addon!", __FUNCTION__, CONTROL_START_SETTING - CONTROL_START_SECTION);
620 break;
621 }
622
623 // add the category button
624 if (button && group)
625 {
626 button->SetID(buttonID++);
627 button->SetLabel(label);
628 button->SetVisible(true);
629 group->AddControl(button);
630 }
631
632 // grab a local copy of all the settings in this category
633 const TiXmlElement *setting = category->FirstChildElement("setting");
634 while (setting)
635 {
636 const std::string id = XMLUtils::GetAttribute(setting, "id");
637 if (!id.empty())
638 m_settings[id] = m_addon->GetSetting(id);
639 setting = setting->NextSiblingElement("setting");
640 }
641 category = category->NextSiblingElement("category");
642 }
643 m_totalSections = buttonID - CONTROL_START_SECTION;
644}
645
646void CGUIDialogAddonSettings::CreateControls()
647{
648 FreeControls();
649
650 CGUISpinControlEx *pOriginalSpin = dynamic_cast<CGUISpinControlEx*>(GetControl(CONTROL_DEFAULT_SPIN));
651 CGUIRadioButtonControl *pOriginalRadioButton = dynamic_cast<CGUIRadioButtonControl *>(GetControl(CONTROL_DEFAULT_RADIOBUTTON));
652 CGUIButtonControl *pOriginalButton = dynamic_cast<CGUIButtonControl *>(GetControl(CONTROL_DEFAULT_BUTTON));
653 CGUIImage *pOriginalImage = dynamic_cast<CGUIImage *>(GetControl(CONTROL_DEFAULT_SEPARATOR));
654 CGUILabelControl *pOriginalLabel = dynamic_cast<CGUILabelControl *>(GetControl(CONTROL_DEFAULT_LABEL_SEPARATOR));
655 CGUISettingsSliderControl *pOriginalSlider = dynamic_cast<CGUISettingsSliderControl *>(GetControl(CONTROL_DEFAULT_SLIDER));
656
657 if (!m_addon || !pOriginalSpin || !pOriginalRadioButton || !pOriginalButton || !pOriginalImage
658 || !pOriginalLabel || !pOriginalSlider)
659 return;
660
661 pOriginalSpin->SetVisible(false);
662 pOriginalRadioButton->SetVisible(false);
663 pOriginalButton->SetVisible(false);
664 pOriginalImage->SetVisible(false);
665 pOriginalLabel->SetVisible(false);
666 pOriginalSlider->SetVisible(false);
667
668 CGUIControlGroupList *group = dynamic_cast<CGUIControlGroupList *>(GetControl(CONTROL_SETTINGS_AREA));
669 if (!group)
670 return;
671
672 // set our dialog heading
673 SET_CONTROL_LABEL(CONTROL_HEADING_LABEL, m_strHeading);
674
675 CGUIControl* pControl = NULL;
676 int controlId = CONTROL_START_SETTING;
677 const TiXmlElement *setting = GetFirstSetting();
678 while (setting)
679 {
680 const std::string type = XMLUtils::GetAttribute(setting, "type");
681 const std::string id = XMLUtils::GetAttribute(setting, "id");
682 const std::string values = XMLUtils::GetAttribute(setting, "values");
683 const std::string lvalues = XMLUtils::GetAttribute(setting, "lvalues");
684 const std::string entries = XMLUtils::GetAttribute(setting, "entries");
685 const std::string defaultVal = XMLUtils::GetAttribute(setting, "default");
686 const std::string subsetting = XMLUtils::GetAttribute(setting, "subsetting");
687 const std::string label = GetString(setting->Attribute("label"), subsetting == "true");
688
689 bool bSort = XMLUtils::GetAttribute(setting, "sort") == "yes";
690 if (!type.empty())
691 {
692 bool isAddonSetting = false;
693 if (type == "text" || type == "ipaddress"
694 || type == "number" || type == "video"
695 || type == "audio" || type == "image"
696 || type == "folder" || type == "executable"
697 || type == "file" || type == "action"
698 || type == "date" || type == "time"
699 || type == "select" || (isAddonSetting = type == "addon"))
700 {
701 pControl = new CGUIButtonControl(*pOriginalButton);
702 if (!pControl) return;
703 ((CGUIButtonControl *)pControl)->SetLabel(label);
704 if (!id.empty())
705 {
706 std::string value = m_settings[id];
707 m_buttonValues[id] = value;
708 // get any option to test for hidden
709 const std::string option = XMLUtils::GetAttribute(setting, "option");
710 if (option == "urlencoded")
711 value = CURL::Decode(value);
712 else if (option == "hidden")
713 {
714 std::string hiddenText;
715 hiddenText.append(value.size(), L'*');
716 ((CGUIButtonControl *)pControl)->SetLabel2(hiddenText);
717 }
718 else
719 {
720 if (isAddonSetting)
721 ((CGUIButtonControl *)pControl)->SetLabel2(GetAddonNames(value));
722 else if (type == "select" && !lvalues.empty())
723 {
724 vector<string> valuesVec = StringUtils::Split(lvalues, '|');
725 int selected = atoi(value.c_str());
726 if (selected >= 0 && selected < (int)valuesVec.size())
727 {
728 std::string label = m_addon->GetString(atoi(valuesVec[selected].c_str()));
729 if (label.empty())
730 label = g_localizeStrings.Get(atoi(valuesVec[selected].c_str()));
731 ((CGUIButtonControl *)pControl)->SetLabel2(label);
732 }
733 }
734 else
735 ((CGUIButtonControl *)pControl)->SetLabel2(value);
736 }
737 }
738 else
739 ((CGUIButtonControl *)pControl)->SetLabel2(defaultVal);
740 }
741 else if (type == "bool" && !id.empty())
742 {
743 pControl = new CGUIRadioButtonControl(*pOriginalRadioButton);
744 if (!pControl) return;
745 ((CGUIRadioButtonControl *)pControl)->SetLabel(label);
746 ((CGUIRadioButtonControl *)pControl)->SetSelected(m_settings[id] == "true");
747 }
748 else if ((type == "enum" || type == "labelenum") && !id.empty())
749 {
750 vector<std::string> valuesVec;
751 vector<std::string> entryVec;
752
753 pControl = new CGUISpinControlEx(*pOriginalSpin);
754 if (!pControl) return;
755 ((CGUISpinControlEx *)pControl)->SetText(label);
756
757 if (!lvalues.empty())
758 StringUtils::Tokenize(lvalues, valuesVec, "|");
759 else if (values == "$HOURS")
760 {
761 for (unsigned int i = 0; i < 24; i++)
762 {
763 CDateTime time(2000, 1, 1, i, 0, 0);
764 valuesVec.push_back(g_infoManager.LocalizeTime(time, TIME_FORMAT_HH_MM_XX));
765 }
766 }
767 else
768 StringUtils::Tokenize(values, valuesVec, "|");
769 if (!entries.empty())
770 StringUtils::Tokenize(entries, entryVec, "|");
771
772 if(bSort && type == "labelenum")
773 std::sort(valuesVec.begin(), valuesVec.end(), sortstringbyname());
774
775 for (unsigned int i = 0; i < valuesVec.size(); i++)
776 {
777 int iAdd = i;
778 if (entryVec.size() > i)
779 iAdd = atoi(entryVec[i].c_str());
780 if (!lvalues.empty())
781 {
782 std::string replace = m_addon->GetString(atoi(valuesVec[i].c_str()));
783 if (replace.empty())
784 replace = g_localizeStrings.Get(atoi(valuesVec[i].c_str()));
785 ((CGUISpinControlEx *)pControl)->AddLabel(replace, iAdd);
786 }
787 else
788 ((CGUISpinControlEx *)pControl)->AddLabel(valuesVec[i], iAdd);
789 }
790 if (type == "labelenum")
791 { // need to run through all our settings and find the one that matches
792 ((CGUISpinControlEx*) pControl)->SetValueFromLabel(m_settings[id]);
793 }
794 else
795 ((CGUISpinControlEx*) pControl)->SetValue(atoi(m_settings[id].c_str()));
796
797 }
798 else if (type == "fileenum" && !id.empty())
799 {
800 pControl = new CGUISpinControlEx(*pOriginalSpin);
801 if (!pControl) return;
802 ((CGUISpinControlEx *)pControl)->SetText(label);
803 ((CGUISpinControlEx *)pControl)->SetFloatValue(1.0f);
804
805 vector<std::string> items = GetFileEnumValues(values, XMLUtils::GetAttribute(setting, "mask"), XMLUtils::GetAttribute(setting, "option"));
806 for (unsigned int i = 0; i < items.size(); ++i)
807 {
808 ((CGUISpinControlEx *)pControl)->AddLabel(items[i], i);
809 if (StringUtils::EqualsNoCase(items[i], m_settings[id]))
810 ((CGUISpinControlEx *)pControl)->SetValue(i);
811 }
812 }
813 // Sample: <setting id="mysettingname" type="rangeofnum" label="30000" rangestart="0" rangeend="100" elements="11" valueformat="30001" default="0" />
814 // in strings.xml: <string id="30001">%2.0f mp</string>
815 // creates 11 piece, text formated number labels from 0 to 100
816 else if (type == "rangeofnum" && !id.empty())
817 {
818 pControl = new CGUISpinControlEx(*pOriginalSpin);
819 if (!pControl)
820 return;
821 ((CGUISpinControlEx *)pControl)->SetText(label);
822 ((CGUISpinControlEx *)pControl)->SetFloatValue(1.0f);
823
824 double rangestart = 0, rangeend = 1;
825 setting->Attribute("rangestart", &rangestart);
826 setting->Attribute("rangeend", &rangeend);
827
828 int elements = 2;
829 setting->Attribute("elements", &elements);
830
831 std::string valueformat;
832 if (setting->Attribute("valueformat"))
833 valueformat = m_addon->GetString(atoi(setting->Attribute("valueformat")));
834 for (int i = 0; i < elements; i++)
835 {
836 std::string valuestring;
837 if (elements < 2)
838 valuestring = StringUtils::Format(valueformat.c_str(), rangestart);
839 else
840 valuestring = StringUtils::Format(valueformat.c_str(), rangestart+(rangeend-rangestart)/(elements-1)*i);
841 ((CGUISpinControlEx *)pControl)->AddLabel(valuestring, i);
842 }
843 ((CGUISpinControlEx *)pControl)->SetValue(atoi(m_settings[id].c_str()));
844 }
845 // Sample: <setting id="mysettingname" type="slider" label="30000" range="5,5,60" option="int" default="5"/>
846 // to make ints from 5-60 with 5 steps
847 else if (type == "slider" && !id.empty())
848 {
849 pControl = new CGUISettingsSliderControl(*pOriginalSlider);
850 if (!pControl) return;
851 ((CGUISettingsSliderControl *)pControl)->SetText(label);
852
853 float fMin = 0.0f;
854 float fMax = 100.0f;
855 float fInc = 1.0f;
856 vector<std::string> range = StringUtils::Split(XMLUtils::GetAttribute(setting, "range"), ',');
857 if (range.size() > 1)
858 {
859 fMin = (float)atof(range[0].c_str());
860 if (range.size() > 2)
861 {
862 fMax = (float)atof(range[2].c_str());
863 fInc = (float)atof(range[1].c_str());
864 }
865 else
866 fMax = (float)atof(range[1].c_str());
867 }
868
869 std::string option = XMLUtils::GetAttribute(setting, "option");
870 int iType=0;
871
872 if (option.empty() || StringUtils::EqualsNoCase(option, "float"))
873 iType = SLIDER_CONTROL_TYPE_FLOAT;
874 else if (StringUtils::EqualsNoCase(option, "int"))
875 iType = SLIDER_CONTROL_TYPE_INT;
876 else if (StringUtils::EqualsNoCase(option, "percent"))
877 iType = SLIDER_CONTROL_TYPE_PERCENTAGE;
878
879 ((CGUISettingsSliderControl *)pControl)->SetType(iType);
880 ((CGUISettingsSliderControl *)pControl)->SetFloatRange(fMin, fMax);
881 ((CGUISettingsSliderControl *)pControl)->SetFloatInterval(fInc);
882 ((CGUISettingsSliderControl *)pControl)->SetFloatValue((float)atof(m_settings[id].c_str()));
883 }
884 else if (type == "lsep")
885 {
886 pControl = new CGUILabelControl(*pOriginalLabel);
887 if (pControl)
888 ((CGUILabelControl *)pControl)->SetLabel(label);
889 }
890 else if (type == "sep")
891 pControl = new CGUIImage(*pOriginalImage);
892 }
893
894 if (pControl)
895 {
896 pControl->SetWidth(group->GetWidth());
897 pControl->SetVisible(true);
898 pControl->SetID(controlId);
899 pControl->AllocResources();
900 group->AddControl(pControl);
901 pControl = NULL;
902 }
903
904 setting = setting->NextSiblingElement("setting");
905 controlId++;
906 }
907 EnableControls();
908}
909
910std::string CGUIDialogAddonSettings::GetAddonNames(const std::string& addonIDslist) const
911{
912 std::string retVal;
913 vector<string> addons = StringUtils::Split(addonIDslist, ',');
914 for (vector<string>::const_iterator it = addons.begin(); it != addons.end() ; ++it)
915 {
916 if (!retVal.empty())
917 retVal += ", ";
918 AddonPtr addon;
919 if (CAddonMgr::Get().GetAddon(*it ,addon))
920 retVal += addon->Name();
921 else
922 retVal += *it;
923 }
924 return retVal;
925}
926
927vector<std::string> CGUIDialogAddonSettings::GetFileEnumValues(const std::string &path, const std::string &mask, const std::string &options) const
928{
929 // Create our base path, used for type "fileenum" settings
930 // replace $PROFILE with the profile path of the plugin/script
931 std::string fullPath = path;
932 if (fullPath.find("$PROFILE") != std::string::npos)
933 StringUtils::Replace(fullPath, "$PROFILE", m_addon->Profile());
934 else
935 fullPath = URIUtils::AddFileToFolder(m_addon->Path(), path);
936
937 bool hideExtensions = StringUtils::EqualsNoCase(options, "hideext");
938 // fetch directory
939 CFileItemList items;
940 if (!mask.empty())
941 CDirectory::GetDirectory(fullPath, items, mask, XFILE::DIR_FLAG_NO_FILE_DIRS);
942 else
943 CDirectory::GetDirectory(fullPath, items, "", XFILE::DIR_FLAG_NO_FILE_DIRS);
944
945 vector<std::string> values;
946 for (int i = 0; i < items.Size(); ++i)
947 {
948 CFileItemPtr pItem = items[i];
949 if ((mask == "/" && pItem->m_bIsFolder) || !pItem->m_bIsFolder)
950 {
951 if (hideExtensions)
952 pItem->RemoveExtension();
953 values.push_back(pItem->GetLabel());
954 }
955 }
956 return values;
957}
958
959// Go over all the settings and set their enabled condition according to the values of the enabled attribute
960void CGUIDialogAddonSettings::EnableControls()
961{
962 int controlId = CONTROL_START_SETTING;
963 const TiXmlElement *setting = GetFirstSetting();
964 while (setting)
965 {
966 const CGUIControl* control = GetControl(controlId);
967 if (control)
968 {
969 // set enable status
970 const char *enable = setting->Attribute("enable");
971 if (enable)
972 ((CGUIControl*) control)->SetEnabled(GetCondition(enable, controlId));
973 else
974 ((CGUIControl*) control)->SetEnabled(true);
975 // set visible status
976 const char *visible = setting->Attribute("visible");
977 if (visible)
978 ((CGUIControl*) control)->SetVisible(GetCondition(visible, controlId));
979 else
980 ((CGUIControl*) control)->SetVisible(true);
981 }
982 setting = setting->NextSiblingElement("setting");
983 controlId++;
984 }
985}
986
987bool CGUIDialogAddonSettings::GetCondition(const std::string &condition, const int controlId)
988{
989 if (condition.empty()) return true;
990
991 bool bCondition = true;
992 bool bCompare = true;
993 bool bControlDependend = false;//flag if the condition depends on another control
994 vector<std::string> conditionVec;
995
996 if (condition.find("+") != std::string::npos)
997 StringUtils::Tokenize(condition, conditionVec, "+");
998 else
999 {
1000 bCondition = false;
1001 bCompare = false;
1002 StringUtils::Tokenize(condition, conditionVec, "|");
1003 }
1004
1005 for (unsigned int i = 0; i < conditionVec.size(); i++)
1006 {
1007 vector<std::string> condVec;
1008 if (!TranslateSingleString(conditionVec[i], condVec)) continue;
1009
1010 const CGUIControl* control2 = GetControl(controlId + atoi(condVec[1].c_str()));
1011 if (!control2)
1012 continue;
1013
1014 bControlDependend = true; //once we are here - this condition depends on another control
1015
1016 std::string value;
1017 switch (control2->GetControlType())
1018 {
1019 case CGUIControl::GUICONTROL_BUTTON:
1020 value = ((CGUIButtonControl*) control2)->GetLabel2();
1021 break;
1022 case CGUIControl::GUICONTROL_RADIO:
1023 value = ((CGUIRadioButtonControl*) control2)->IsSelected() ? "true" : "false";
1024 break;
1025 case CGUIControl::GUICONTROL_SPINEX:
1026 if (((CGUISpinControlEx*) control2)->GetFloatValue() > 0.0f)
1027 value = ((CGUISpinControlEx*) control2)->GetLabel();
1028 else
1029 value = StringUtils::Format("%i", ((CGUISpinControlEx*) control2)->GetValue());
1030 break;
1031 default:
1032 break;
1033 }
1034
1035 if (condVec[0] == "eq")
1036 {
1037 if (bCompare)
1038 bCondition &= StringUtils::EqualsNoCase(value, condVec[2]);
1039 else
1040 bCondition |= StringUtils::EqualsNoCase(value, condVec[2]);
1041 }
1042 else if (condVec[0] == "!eq")
1043 {
1044 if (bCompare)
1045 bCondition &= !StringUtils::EqualsNoCase(value, condVec[2]);
1046 else
1047 bCondition |= !StringUtils::EqualsNoCase(value, condVec[2]);
1048 }
1049 else if (condVec[0] == "gt")
1050 {
1051 if (bCompare)
1052 bCondition &= (atoi(value.c_str()) > atoi(condVec[2].c_str()));
1053 else
1054 bCondition |= (atoi(value.c_str()) > atoi(condVec[2].c_str()));
1055 }
1056 else if (condVec[0] == "lt")
1057 {
1058 if (bCompare)
1059 bCondition &= (atoi(value.c_str()) < atoi(condVec[2].c_str()));
1060 else
1061 bCondition |= (atoi(value.c_str()) < atoi(condVec[2].c_str()));
1062 }
1063 }
1064
1065 if (!bControlDependend)//if condition doesn't depend on another control - try if its an infobool expression
1066 {
1067 bCondition = g_infoManager.EvaluateBool(condition);
1068 }
1069
1070 return bCondition;
1071}
1072
1073bool CGUIDialogAddonSettings::TranslateSingleString(const std::string &strCondition, vector<std::string> &condVec)
1074{
1075 std::string strTest = strCondition;
1076 StringUtils::ToLower(strTest);
1077 StringUtils::Trim(strTest);
1078
1079 size_t pos1 = strTest.find("(");
1080 size_t pos2 = strTest.find(",", pos1);
1081 size_t pos3 = strTest.find(")", pos2);
1082 if (pos1 != std::string::npos &&
1083 pos2 != std::string::npos &&
1084 pos3 != std::string::npos)
1085 {
1086 condVec.push_back(strTest.substr(0, pos1));
1087 condVec.push_back(strTest.substr(pos1 + 1, pos2 - pos1 - 1));
1088 condVec.push_back(strTest.substr(pos2 + 1, pos3 - pos2 - 1));
1089 return true;
1090 }
1091 return false;
1092}
1093
1094std::string CGUIDialogAddonSettings::GetString(const char *value, bool subSetting) const
1095{
1096 if (!value)
1097 return "";
1098 std::string prefix(subSetting ? "- " : "");
1099 if (StringUtils::IsNaturalNumber(value))
1100 return prefix + m_addon->GetString(atoi(value));
1101 return prefix + value;
1102}
1103
1104// Go over all the settings and set their default values
1105void CGUIDialogAddonSettings::SetDefaultSettings()
1106{
1107 if(!m_addon)
1108 return;
1109
1110 const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category");
1111 if (!category) // add a default one...
1112 category = m_addon->GetSettingsXML();
1113
1114 while (category)
1115 {
1116 const TiXmlElement *setting = category->FirstChildElement("setting");
1117 while (setting)
1118 {
1119 const std::string id = XMLUtils::GetAttribute(setting, "id");
1120 const std::string type = XMLUtils::GetAttribute(setting, "type");
1121 const char *value = setting->Attribute("default");
1122 if (!id.empty())
1123 {
1124 if (value)
1125 m_settings[id] = value;
1126 else if (type == "bool")
1127 m_settings[id] = "false";
1128 else if (type == "slider" || type == "enum")
1129 m_settings[id] = "0";
1130 else
1131 m_settings[id] = "";
1132 }
1133 setting = setting->NextSiblingElement("setting");
1134 }
1135 category = category->NextSiblingElement("category");
1136 }
1137 CreateControls();
1138}
1139
1140const TiXmlElement *CGUIDialogAddonSettings::GetFirstSetting() const
1141{
1142 const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category");
1143 if (!category)
1144 category = m_addon->GetSettingsXML();
1145 for (unsigned int i = 0; i < m_currentSection && category; i++)
1146 category = category->NextSiblingElement("category");
1147 if (category)
1148 return category->FirstChildElement("setting");
1149 return NULL;
1150}
1151
1152void CGUIDialogAddonSettings::DoProcess(unsigned int currentTime, CDirtyRegionList &dirtyregions)
1153{
1154 // update status of current section button
1155 bool alphaFaded = false;
1156 CGUIControl *control = GetFirstFocusableControl(CONTROL_START_SECTION + m_currentSection);
1157 if (control && !control->HasFocus())
1158 {
1159 if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
1160 {
1161 control->SetFocus(true);
1162 ((CGUIButtonControl *)control)->SetAlpha(0x80);
1163 alphaFaded = true;
1164 }
1165 else if (control->GetControlType() == CGUIControl::GUICONTROL_TOGGLEBUTTON)
1166 {
1167 control->SetFocus(true);
1168 ((CGUIButtonControl *)control)->SetSelected(true);
1169 alphaFaded = true;
1170 }
1171 }
1172 CGUIDialogBoxBase::DoProcess(currentTime, dirtyregions);
1173 if (alphaFaded && m_active) // dialog may close
1174 {
1175 control->SetFocus(false);
1176 if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
1177 ((CGUIButtonControl *)control)->SetAlpha(0xFF);
1178 else
1179 ((CGUIButtonControl *)control)->SetSelected(false);
1180 }
1181}
1182
1183std::string CGUIDialogAddonSettings::GetCurrentID() const
1184{
1185 if (m_addon)
1186 return m_addon->ID();
1187 return "";
1188}
1189
1190int CGUIDialogAddonSettings::GetDefaultLabelID(int controlId) const
1191{
1192 if (controlId == ID_BUTTON_OK)
1193 return 186;
1194 else if (controlId == ID_BUTTON_CANCEL)
1195 return 222;
1196 else if (controlId == ID_BUTTON_DEFAULT)
1197 return 409;
1198
1199 return CGUIDialogBoxBase::GetDefaultLabelID(controlId);
1200}