2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
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/>.
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 "guilib/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"
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"
56 using namespace ADDON;
57 using XFILE::CDirectory;
59 #define CONTROL_SETTINGS_AREA 2
60 #define CONTROL_DEFAULT_BUTTON 3
61 #define CONTROL_DEFAULT_RADIOBUTTON 4
62 #define CONTROL_DEFAULT_SPIN 5
63 #define CONTROL_DEFAULT_SEPARATOR 6
64 #define CONTROL_DEFAULT_LABEL_SEPARATOR 7
65 #define CONTROL_DEFAULT_SLIDER 8
66 #define CONTROL_SECTION_AREA 9
67 #define CONTROL_DEFAULT_SECTION_BUTTON 13
69 #define ID_BUTTON_OK 10
70 #define ID_BUTTON_CANCEL 11
71 #define ID_BUTTON_DEFAULT 12
72 #define CONTROL_HEADING_LABEL 20
74 #define CONTROL_START_SETTING 100
75 #define CONTROL_START_SECTION 200
77 CGUIDialogAddonSettings::CGUIDialogAddonSettings()
78 : CGUIDialogBoxBase(WINDOW_DIALOG_ADDON_SETTINGS, "DialogAddonSettings.xml")
84 CGUIDialogAddonSettings::~CGUIDialogAddonSettings(void)
88 bool CGUIDialogAddonSettings::OnMessage(CGUIMessage& message)
90 switch (message.GetMessage())
92 case GUI_MSG_WINDOW_DEINIT:
99 int iControl = message.GetSenderId();
100 bool bCloseDialog = false;
102 if (iControl == ID_BUTTON_DEFAULT)
103 SetDefaultSettings();
104 else if (iControl != ID_BUTTON_OK)
105 bCloseDialog = ShowVirtualKeyboard(iControl);
107 if (iControl == ID_BUTTON_OK || iControl == ID_BUTTON_CANCEL || bCloseDialog)
109 if (iControl == ID_BUTTON_OK || bCloseDialog)
119 case GUI_MSG_FOCUSED:
121 CGUIDialogBoxBase::OnMessage(message);
122 int focusedControl = GetFocusedControlID();
123 if (focusedControl >= CONTROL_START_SECTION && focusedControl < (int)(CONTROL_START_SECTION + m_totalSections) &&
124 focusedControl - CONTROL_START_SECTION != (int)m_currentSection)
125 { // changing section
126 UpdateFromControls();
127 m_currentSection = focusedControl - CONTROL_START_SECTION;
132 case GUI_MSG_SETTING_UPDATED:
134 CStdString id = message.GetStringParam(0);
135 CStdString value = message.GetStringParam(1);
136 m_settings[id] = value;
137 if (GetFocusedControl())
139 int iControl = GetFocusedControl()->GetID();
141 CGUIMessage msg(GUI_MSG_SETFOCUS,GetID(),iControl);
147 return CGUIDialogBoxBase::OnMessage(message);
150 bool CGUIDialogAddonSettings::OnAction(const CAction& action)
152 if (action.GetID() == ACTION_DELETE_ITEM)
154 CGUIControl* pControl = GetFocusedControl();
157 int iControl = pControl->GetID();
158 int controlId = CONTROL_START_SETTING;
159 const TiXmlElement* setting = GetFirstSetting();
160 UpdateFromControls();
163 if (controlId == iControl)
165 const char* id = setting->Attribute("id");
166 const char* value = setting->Attribute("default");
167 m_settings[id] = value;
169 CGUIMessage msg(GUI_MSG_SETFOCUS,GetID(),iControl);
173 setting = setting->NextSiblingElement("setting");
178 return CGUIDialogBoxBase::OnAction(action);
181 void CGUIDialogAddonSettings::OnInitWindow()
183 m_currentSection = 0;
187 CGUIDialogBoxBase::OnInitWindow();
190 // \brief Show CGUIDialogOK dialog, then wait for user to dismiss it.
191 bool CGUIDialogAddonSettings::ShowAndGetInput(const AddonPtr &addon, bool saveToDisk /* = true */)
196 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
200 if (addon->HasSettings())
203 CGUIDialogAddonSettings* pDialog = NULL;
204 pDialog = (CGUIDialogAddonSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_ADDON_SETTINGS);
209 CStdString heading = StringUtils::Format("$LOCALIZE[10004] - %s", addon->Name().c_str()); // "Settings - AddonName"
210 pDialog->m_strHeading = heading;
212 pDialog->m_changed = false;
213 pDialog->m_addon = addon;
214 pDialog->m_saveToDisk = saveToDisk;
219 { // addon does not support settings, inform user
220 CGUIDialogOK::ShowAndGetInput(24000,0,24030,0);
226 bool CGUIDialogAddonSettings::ShowVirtualKeyboard(int iControl)
228 int controlId = CONTROL_START_SETTING;
229 bool bCloseDialog = false;
231 const TiXmlElement *setting = GetFirstSetting();
234 if (controlId == iControl)
236 const CGUIControl* control = GetControl(controlId);
237 if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
239 const char *id = setting->Attribute("id");
240 const char *type = setting->Attribute("type");
241 const char *option = setting->Attribute("option");
242 const char *source = setting->Attribute("source");
243 CStdString value = m_buttonValues[id];
244 CStdString label = GetString(setting->Attribute("label"));
246 if (strcmp(type, "text") == 0)
249 bool bHidden = false;
250 bool bEncoded = false;
253 bHidden = (strstr(option, "hidden") != NULL);
254 bEncoded = (strstr(option, "urlencoded") != NULL);
257 value = CURL::Decode(value);
259 if (CGUIKeyboardFactory::ShowAndGetInput(value, label, true, bHidden))
261 // if hidden hide input
264 CStdString hiddenText;
265 hiddenText.append(value.size(), L'*');
266 ((CGUIButtonControl *)control)->SetLabel2(hiddenText);
269 ((CGUIButtonControl*) control)->SetLabel2(value);
271 value = CURL::Encode(value);
274 else if (strcmp(type, "number") == 0 && CGUIDialogNumeric::ShowAndGetNumber(value, label))
276 ((CGUIButtonControl*) control)->SetLabel2(value);
278 else if (strcmp(type, "ipaddress") == 0 && CGUIDialogNumeric::ShowAndGetIPAddress(value, label))
280 ((CGUIButtonControl*) control)->SetLabel2(value);
282 else if (strcmpi(type, "select") == 0)
284 CGUIDialogSelect *pDlg = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
287 pDlg->SetHeading(label.c_str());
291 vector<std::string> valuesVec;
292 if (setting->Attribute("values"))
293 StringUtils::Tokenize(setting->Attribute("values"), valuesVec, "|");
294 else if (setting->Attribute("lvalues"))
296 StringUtils::Tokenize(setting->Attribute("lvalues"), valuesVec, "|");
297 for (unsigned int i = 0; i < valuesVec.size(); i++)
299 if (i == (unsigned int)atoi(value))
301 CStdString localized = m_addon->GetString(atoi(valuesVec[i].c_str()));
302 if (localized.empty())
303 localized = g_localizeStrings.Get(atoi(valuesVec[i].c_str()));
304 valuesVec[i] = localized;
309 valuesVec = GetFileEnumValues(source, setting->Attribute("mask"), setting->Attribute("option"));
312 for (unsigned int i = 0; i < valuesVec.size(); i++)
314 pDlg->Add(valuesVec[i]);
315 if (selected == (int)i || (selected < 0 && StringUtils::EqualsNoCase(valuesVec[i], value)))
316 pDlg->SetSelected(i); // FIXME: the SetSelected() does not select "i", it always defaults to the first position
319 int iSelected = pDlg->GetSelectedLabel();
322 if (setting->Attribute("lvalues"))
323 value = StringUtils::Format("%i", iSelected);
325 value = valuesVec[iSelected];
326 ((CGUIButtonControl*) control)->SetLabel2(valuesVec[iSelected]);
330 else if (strcmpi(type, "audio") == 0 || strcmpi(type, "video") == 0 ||
331 strcmpi(type, "image") == 0 || strcmpi(type, "executable") == 0 ||
332 strcmpi(type, "file") == 0 || strcmpi(type, "folder") == 0)
335 VECSOURCES *shares = NULL;
336 if (source && strcmpi(source, "") != 0)
337 shares = CMediaSourceSettings::Get().GetSources(source);
339 VECSOURCES localShares;
342 VECSOURCES networkShares;
343 g_mediaManager.GetLocalDrives(localShares);
344 if (!source || strcmpi(source, "local") != 0)
345 g_mediaManager.GetNetworkLocations(localShares);
347 else // always append local drives
349 localShares = *shares;
350 g_mediaManager.GetLocalDrives(localShares);
353 if (strcmpi(type, "folder") == 0)
356 bool bWriteOnly = false;
358 bWriteOnly = (strcmpi(option, "writeable") == 0);
360 if (CGUIDialogFileBrowser::ShowAndGetDirectory(localShares, label, value, bWriteOnly))
361 ((CGUIButtonControl*) control)->SetLabel2(value);
363 else if (strcmpi(type, "image") == 0)
365 if (CGUIDialogFileBrowser::ShowAndGetImage(localShares, label, value))
366 ((CGUIButtonControl*) control)->SetLabel2(value);
370 // set the proper mask
372 if (setting->Attribute("mask"))
374 strMask = setting->Attribute("mask");
375 // convert mask qualifiers
376 StringUtils::Replace(strMask, "$AUDIO", g_advancedSettings.m_musicExtensions);
377 StringUtils::Replace(strMask, "$VIDEO", g_advancedSettings.m_videoExtensions);
378 StringUtils::Replace(strMask, "$IMAGE", g_advancedSettings.m_pictureExtensions);
379 #if defined(_WIN32_WINNT)
380 StringUtils::Replace(strMask, "$EXECUTABLE", ".exe|.bat|.cmd|.py");
382 StringUtils::Replace(strMask, "$EXECUTABLE", "");
387 if (strcmpi(type, "video") == 0)
388 strMask = g_advancedSettings.m_videoExtensions;
389 else if (strcmpi(type, "audio") == 0)
390 strMask = g_advancedSettings.m_musicExtensions;
391 else if (strcmpi(type, "executable") == 0)
392 #if defined(_WIN32_WINNT)
393 strMask = ".exe|.bat|.cmd|.py";
400 bool bUseThumbs = false;
401 bool bUseFileDirectories = false;
404 vector<CStdString> options;
405 StringUtils::SplitString(option, "|", options);
406 bUseThumbs = find(options.begin(), options.end(), "usethumbs") != options.end();
407 bUseFileDirectories = find(options.begin(), options.end(), "treatasfolder") != options.end();
410 if (CGUIDialogFileBrowser::ShowAndGetFile(localShares, strMask, label, value, bUseThumbs, bUseFileDirectories))
411 ((CGUIButtonControl*) control)->SetLabel2(value);
414 else if (strcmpi(type, "action") == 0)
416 CStdString action = setting->Attribute("action");
419 // replace $CWD with the url of plugin/script
420 StringUtils::Replace(action, "$CWD", m_addon->Path());
421 StringUtils::Replace(action, "$ID", m_addon->ID());
423 bCloseDialog = (strcmpi(option, "close") == 0);
424 CApplicationMessenger::Get().ExecBuiltIn(action);
427 else if (strcmp(type, "date") == 0)
431 date.SetFromDBDate(value);
433 date.GetAsSystemTime(timedate);
434 if(CGUIDialogNumeric::ShowAndGetDate(timedate, label))
437 value = date.GetAsDBDate();
438 ((CGUIButtonControl*) control)->SetLabel2(value);
441 else if (strcmp(type, "time") == 0)
444 if (value.size() >= 5)
447 timedate.wHour = atoi(value.substr(0, 2).c_str());
448 timedate.wMinute = atoi(value.substr(3, 2).c_str());
450 if (CGUIDialogNumeric::ShowAndGetTime(timedate, label))
452 value = StringUtils::Format("%02d:%02d", timedate.wHour, timedate.wMinute);
453 ((CGUIButtonControl*) control)->SetLabel2(value);
456 else if (strcmp(type, "addon") == 0)
458 const char *strType = setting->Attribute("addontype");
461 CStdStringArray addonTypes;
462 StringUtils::SplitString(strType, ",", addonTypes);
463 vector<ADDON::TYPE> types;
464 for (unsigned int i = 0 ; i < addonTypes.size() ; i++)
466 StringUtils::Trim(addonTypes[i]);
467 ADDON::TYPE type = TranslateType(addonTypes[i]);
468 if (type != ADDON_UNKNOWN)
469 types.push_back(type);
471 if (types.size() > 0)
473 const char *strMultiselect = setting->Attribute("multiselect");
474 bool multiSelect = strMultiselect && strcmpi(strMultiselect, "true") == 0;
477 // construct vector of addon IDs (IDs are comma seperated in single string)
478 CStdStringArray addonIDs;
479 StringUtils::SplitString(value, ",", addonIDs);
480 if (CGUIWindowAddonBrowser::SelectAddonID(types, addonIDs, false) == 1)
482 StringUtils::JoinString(addonIDs, ",", value);
483 ((CGUIButtonControl*) control)->SetLabel2(GetAddonNames(value));
486 else // no need of string splitting/joining if we select only 1 addon
487 if (CGUIWindowAddonBrowser::SelectAddonID(types, value, false) == 1)
488 ((CGUIButtonControl*) control)->SetLabel2(GetAddonNames(value));
492 m_buttonValues[id] = value;
496 setting = setting->NextSiblingElement("setting");
503 void CGUIDialogAddonSettings::UpdateFromControls()
505 int controlID = CONTROL_START_SETTING;
506 const TiXmlElement *setting = GetFirstSetting();
509 CStdString id = setting->Attribute("id");
510 const char *type = setting->Attribute("type");
511 const CGUIControl* control = GetControl(controlID++);
516 switch (control->GetControlType())
518 case CGUIControl::GUICONTROL_BUTTON:
519 value = m_buttonValues[id];
521 case CGUIControl::GUICONTROL_RADIO:
522 value = ((CGUIRadioButtonControl*) control)->IsSelected() ? "true" : "false";
524 case CGUIControl::GUICONTROL_SPINEX:
525 if (strcmpi(type, "fileenum") == 0 || strcmpi(type, "labelenum") == 0)
526 value = ((CGUISpinControlEx*) control)->GetLabel();
528 value = StringUtils::Format("%i", ((CGUISpinControlEx*) control)->GetValue());
530 case CGUIControl::GUICONTROL_SETTINGS_SLIDER:
532 CStdString option = setting->Attribute("option");
533 if (option.size() == 0 || StringUtils::EqualsNoCase(option, "float"))
534 value = StringUtils::Format("%f", ((CGUISettingsSliderControl *)control)->GetFloatValue());
536 value = StringUtils::Format("%i", ((CGUISettingsSliderControl *)control)->GetIntValue());
542 m_settings[id] = value;
545 setting = setting->NextSiblingElement("setting");
549 void CGUIDialogAddonSettings::SaveSettings(void)
551 UpdateFromControls();
553 for (map<CStdString, CStdString>::iterator i = m_settings.begin(); i != m_settings.end(); ++i)
554 m_addon->UpdateSetting(i->first, i->second);
558 m_addon->SaveSettings();
562 void CGUIDialogAddonSettings::FreeSections()
564 CGUIControlGroupList *group = (CGUIControlGroupList *)GetControl(CONTROL_SECTION_AREA);
567 group->FreeResources();
571 m_buttonValues.clear();
575 void CGUIDialogAddonSettings::FreeControls()
577 // clear the category group
578 CGUIControlGroupList *control = (CGUIControlGroupList *)GetControl(CONTROL_SETTINGS_AREA);
581 control->FreeResources();
586 void CGUIDialogAddonSettings::CreateSections()
588 CGUIControlGroupList *group = (CGUIControlGroupList *)GetControl(CONTROL_SECTION_AREA);
589 CGUIButtonControl *originalButton = (CGUIButtonControl *)GetControl(CONTROL_DEFAULT_SECTION_BUTTON);
594 originalButton->SetVisible(false);
596 // clear the category group
599 // grab our categories
600 const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category");
601 if (!category) // add a default one...
602 category = m_addon->GetSettingsXML();
604 int buttonID = CONTROL_START_SECTION;
607 CGUIButtonControl *button = originalButton ? originalButton->Clone() : NULL;
609 CStdString label = GetString(category->Attribute("label"));
611 label = g_localizeStrings.Get(128);
613 // add the category button
616 button->SetID(buttonID++);
617 button->SetLabel(label);
618 button->SetVisible(true);
619 group->AddControl(button);
622 // grab a local copy of all the settings in this category
623 const TiXmlElement *setting = category->FirstChildElement("setting");
626 const char *id = setting->Attribute("id");
628 m_settings[id] = m_addon->GetSetting(id);
629 setting = setting->NextSiblingElement("setting");
631 category = category->NextSiblingElement("category");
633 m_totalSections = buttonID - CONTROL_START_SECTION;
636 void CGUIDialogAddonSettings::CreateControls()
640 CGUISpinControlEx *pOriginalSpin = (CGUISpinControlEx*)GetControl(CONTROL_DEFAULT_SPIN);
641 CGUIRadioButtonControl *pOriginalRadioButton = (CGUIRadioButtonControl *)GetControl(CONTROL_DEFAULT_RADIOBUTTON);
642 CGUIButtonControl *pOriginalButton = (CGUIButtonControl *)GetControl(CONTROL_DEFAULT_BUTTON);
643 CGUIImage *pOriginalImage = (CGUIImage *)GetControl(CONTROL_DEFAULT_SEPARATOR);
644 CGUILabelControl *pOriginalLabel = (CGUILabelControl *)GetControl(CONTROL_DEFAULT_LABEL_SEPARATOR);
645 CGUISettingsSliderControl *pOriginalSlider = (CGUISettingsSliderControl *)GetControl(CONTROL_DEFAULT_SLIDER);
647 if (!m_addon || !pOriginalSpin || !pOriginalRadioButton || !pOriginalButton || !pOriginalImage
648 || !pOriginalLabel || !pOriginalSlider)
651 pOriginalSpin->SetVisible(false);
652 pOriginalRadioButton->SetVisible(false);
653 pOriginalButton->SetVisible(false);
654 pOriginalImage->SetVisible(false);
655 pOriginalLabel->SetVisible(false);
656 pOriginalSlider->SetVisible(false);
658 // clear the category group
659 CGUIControlGroupList *group = (CGUIControlGroupList *)GetControl(CONTROL_SETTINGS_AREA);
663 // set our dialog heading
664 SET_CONTROL_LABEL(CONTROL_HEADING_LABEL, m_strHeading);
666 CGUIControl* pControl = NULL;
667 int controlId = CONTROL_START_SETTING;
668 const TiXmlElement *setting = GetFirstSetting();
671 const char *type = setting->Attribute("type");
672 const char *id = setting->Attribute("id");
674 if (setting->Attribute("values"))
675 values = setting->Attribute("values");
677 if (setting->Attribute("lvalues"))
678 lvalues = setting->Attribute("lvalues");
680 if (setting->Attribute("entries"))
681 entries = setting->Attribute("entries");
682 CStdString defaultValue;
683 if (setting->Attribute("default"))
684 defaultValue= setting->Attribute("default");
685 const char *subsetting = setting->Attribute("subsetting");
686 CStdString label = GetString(setting->Attribute("label"), subsetting && 0 == strcmpi(subsetting, "true"));
689 const char *sort = setting->Attribute("sort");
690 if (sort && (strcmp(sort, "yes") == 0))
695 bool isAddonSetting = false;
696 if (strcmpi(type, "text") == 0 || strcmpi(type, "ipaddress") == 0 ||
697 strcmpi(type, "number") == 0 ||strcmpi(type, "video") == 0 ||
698 strcmpi(type, "audio") == 0 || strcmpi(type, "image") == 0 ||
699 strcmpi(type, "folder") == 0 || strcmpi(type, "executable") == 0 ||
700 strcmpi(type, "file") == 0 || strcmpi(type, "action") == 0 ||
701 strcmpi(type, "date") == 0 || strcmpi(type, "time") == 0 ||
702 strcmpi(type, "select") == 0 || (isAddonSetting = strcmpi(type, "addon") == 0))
704 pControl = new CGUIButtonControl(*pOriginalButton);
705 if (!pControl) return;
706 ((CGUIButtonControl *)pControl)->SetLabel(label);
709 CStdString value = m_settings[id];
710 m_buttonValues[id] = value;
711 // get any option to test for hidden
712 const char *option = setting->Attribute("option");
713 if (option && (strstr(option, "urlencoded")))
714 value = CURL::Decode(value);
715 if (option && (strstr(option, "hidden")))
717 CStdString hiddenText;
718 hiddenText.append(value.size(), L'*');
719 ((CGUIButtonControl *)pControl)->SetLabel2(hiddenText);
724 ((CGUIButtonControl *)pControl)->SetLabel2(GetAddonNames(value));
725 else if (strcmpi(type, "select") == 0 && !lvalues.empty())
727 vector<string> valuesVec = StringUtils::Split(lvalues, "|");
728 int selected = atoi(value.c_str());
729 if (selected >= 0 && selected < (int)valuesVec.size())
731 CStdString label = m_addon->GetString(atoi(valuesVec[selected].c_str()));
733 label = g_localizeStrings.Get(atoi(valuesVec[selected].c_str()));
734 ((CGUIButtonControl *)pControl)->SetLabel2(label);
738 ((CGUIButtonControl *)pControl)->SetLabel2(value);
742 ((CGUIButtonControl *)pControl)->SetLabel2(defaultValue);
744 else if (strcmpi(type, "bool") == 0)
746 pControl = new CGUIRadioButtonControl(*pOriginalRadioButton);
747 if (!pControl) return;
748 ((CGUIRadioButtonControl *)pControl)->SetLabel(label);
749 ((CGUIRadioButtonControl *)pControl)->SetSelected(m_settings[id] == "true");
751 else if (strcmpi(type, "enum") == 0 || strcmpi(type, "labelenum") == 0)
753 vector<std::string> valuesVec;
754 vector<std::string> entryVec;
756 pControl = new CGUISpinControlEx(*pOriginalSpin);
757 if (!pControl) return;
758 ((CGUISpinControlEx *)pControl)->SetText(label);
760 if (!lvalues.empty())
761 StringUtils::Tokenize(lvalues, valuesVec, "|");
762 else if (values.Equals("$HOURS"))
764 for (unsigned int i = 0; i < 24; i++)
766 CDateTime time(2000, 1, 1, i, 0, 0);
767 valuesVec.push_back(g_infoManager.LocalizeTime(time, TIME_FORMAT_HH_MM_XX));
771 StringUtils::Tokenize(values, valuesVec, "|");
772 if (!entries.empty())
773 StringUtils::Tokenize(entries, entryVec, "|");
775 if(bSort && strcmpi(type, "labelenum") == 0)
776 std::sort(valuesVec.begin(), valuesVec.end(), sortstringbyname());
778 for (unsigned int i = 0; i < valuesVec.size(); i++)
781 if (entryVec.size() > i)
782 iAdd = atoi(entryVec[i].c_str());
783 if (!lvalues.empty())
785 CStdString replace = m_addon->GetString(atoi(valuesVec[i].c_str()));
787 replace = g_localizeStrings.Get(atoi(valuesVec[i].c_str()));
788 ((CGUISpinControlEx *)pControl)->AddLabel(replace, iAdd);
791 ((CGUISpinControlEx *)pControl)->AddLabel(valuesVec[i], iAdd);
793 if (strcmpi(type, "labelenum") == 0)
794 { // need to run through all our settings and find the one that matches
795 ((CGUISpinControlEx*) pControl)->SetValueFromLabel(m_settings[id]);
798 ((CGUISpinControlEx*) pControl)->SetValue(atoi(m_settings[id]));
801 else if (strcmpi(type, "fileenum") == 0)
803 pControl = new CGUISpinControlEx(*pOriginalSpin);
804 if (!pControl) return;
805 ((CGUISpinControlEx *)pControl)->SetText(label);
806 ((CGUISpinControlEx *)pControl)->SetFloatValue(1.0f);
808 vector<std::string> items = GetFileEnumValues(values, setting->Attribute("mask"), setting->Attribute("option"));
809 for (unsigned int i = 0; i < items.size(); ++i)
811 ((CGUISpinControlEx *)pControl)->AddLabel(items[i], i);
812 if (StringUtils::EqualsNoCase(items[i], m_settings[id]))
813 ((CGUISpinControlEx *)pControl)->SetValue(i);
816 // Sample: <setting id="mysettingname" type="rangeofnum" label="30000" rangestart="0" rangeend="100" elements="11" valueformat="30001" default="0" />
817 // in strings.xml: <string id="30001">%2.0f mp</string>
818 // creates 11 piece, text formated number labels from 0 to 100
819 else if (strcmpi(type, "rangeofnum") == 0)
821 pControl = new CGUISpinControlEx(*pOriginalSpin);
824 ((CGUISpinControlEx *)pControl)->SetText(label);
825 ((CGUISpinControlEx *)pControl)->SetFloatValue(1.0f);
827 double rangestart = 0;
828 if (setting->Attribute("rangestart"))
829 rangestart = atof(setting->Attribute("rangestart"));
831 if (setting->Attribute("rangeend"))
832 rangeend = atof(setting->Attribute("rangeend"));
834 if (setting->Attribute("elements"))
835 elements = atoi(setting->Attribute("elements"));
836 CStdString valueformat;
837 if (setting->Attribute("valueformat"))
838 valueformat = m_addon->GetString(atoi(setting->Attribute("valueformat")));
839 for (int i = 0; i < elements; i++)
841 CStdString valuestring;
843 valuestring = StringUtils::Format(valueformat.c_str(), rangestart);
845 valuestring = StringUtils::Format(valueformat.c_str(), rangestart+(rangeend-rangestart)/(elements-1)*i);
846 ((CGUISpinControlEx *)pControl)->AddLabel(valuestring, i);
848 ((CGUISpinControlEx *)pControl)->SetValue(atoi(m_settings[id]));
850 // Sample: <setting id="mysettingname" type="slider" label="30000" range="5,5,60" option="int" default="5"/>
851 // to make ints from 5-60 with 5 steps
852 else if (strcmpi(type, "slider") == 0)
854 pControl = new CGUISettingsSliderControl(*pOriginalSlider);
855 if (!pControl) return;
856 ((CGUISettingsSliderControl *)pControl)->SetText(label);
861 vector<CStdString> range;
862 StringUtils::SplitString(setting->Attribute("range"), ",", range);
863 if (range.size() > 1)
865 fMin = (float)atof(range[0]);
866 if (range.size() > 2)
868 fMax = (float)atof(range[2]);
869 fInc = (float)atof(range[1]);
872 fMax = (float)atof(range[1]);
875 CStdString option = setting->Attribute("option");
878 if (option.size() == 0 || StringUtils::EqualsNoCase(option, "float"))
879 iType = SPIN_CONTROL_TYPE_FLOAT;
880 else if (StringUtils::EqualsNoCase(option, "int"))
881 iType = SPIN_CONTROL_TYPE_INT;
882 else if (StringUtils::EqualsNoCase(option, "percent"))
885 ((CGUISettingsSliderControl *)pControl)->SetType(iType);
886 ((CGUISettingsSliderControl *)pControl)->SetFloatRange(fMin, fMax);
887 ((CGUISettingsSliderControl *)pControl)->SetFloatInterval(fInc);
888 ((CGUISettingsSliderControl *)pControl)->SetFloatValue((float)atof(m_settings[id]));
890 else if (strcmpi(type, "lsep") == 0)
892 pControl = new CGUILabelControl(*pOriginalLabel);
894 ((CGUILabelControl *)pControl)->SetLabel(label);
896 else if (strcmpi(type, "sep") == 0)
897 pControl = new CGUIImage(*pOriginalImage);
902 pControl->SetWidth(group->GetWidth());
903 pControl->SetVisible(true);
904 pControl->SetID(controlId);
905 pControl->AllocResources();
906 group->AddControl(pControl);
910 setting = setting->NextSiblingElement("setting");
912 if (controlId >= CONTROL_START_SECTION)
914 CLog::Log(LOGERROR, "%s - cannot have more than %d controls per category - simplify your addon!", __FUNCTION__, CONTROL_START_SECTION - CONTROL_START_SETTING);
921 CStdString CGUIDialogAddonSettings::GetAddonNames(const CStdString& addonIDslist) const
924 CStdStringArray addons;
925 StringUtils::SplitString(addonIDslist, ",", addons);
926 for (CStdStringArray::const_iterator it = addons.begin(); it != addons.end() ; it ++)
931 if (CAddonMgr::Get().GetAddon(*it ,addon))
932 retVal += addon->Name();
939 vector<std::string> CGUIDialogAddonSettings::GetFileEnumValues(const CStdString &path, const CStdString &mask, const CStdString &options) const
941 // Create our base path, used for type "fileenum" settings
942 // replace $PROFILE with the profile path of the plugin/script
943 CStdString fullPath = path;
944 if (fullPath.find("$PROFILE") != std::string::npos)
945 StringUtils::Replace(fullPath, "$PROFILE", m_addon->Profile());
947 fullPath = URIUtils::AddFileToFolder(m_addon->Path(), path);
949 bool hideExtensions = StringUtils::EqualsNoCase(options, "hideext");
953 CDirectory::GetDirectory(fullPath, items, mask, XFILE::DIR_FLAG_NO_FILE_DIRS);
955 CDirectory::GetDirectory(fullPath, items, "", XFILE::DIR_FLAG_NO_FILE_DIRS);
957 vector<std::string> values;
958 for (int i = 0; i < items.Size(); ++i)
960 CFileItemPtr pItem = items[i];
961 if ((mask.Equals("/") && pItem->m_bIsFolder) || !pItem->m_bIsFolder)
964 pItem->RemoveExtension();
965 values.push_back(pItem->GetLabel());
971 // Go over all the settings and set their enabled condition according to the values of the enabled attribute
972 void CGUIDialogAddonSettings::EnableControls()
974 int controlId = CONTROL_START_SETTING;
975 const TiXmlElement *setting = GetFirstSetting();
978 const CGUIControl* control = GetControl(controlId);
982 if (setting->Attribute("enable"))
983 ((CGUIControl*) control)->SetEnabled(GetCondition(setting->Attribute("enable"), controlId));
985 ((CGUIControl*) control)->SetEnabled(true);
986 // set visible status
987 if (setting->Attribute("visible"))
988 ((CGUIControl*) control)->SetVisible(GetCondition(setting->Attribute("visible"), controlId));
990 ((CGUIControl*) control)->SetVisible(true);
992 setting = setting->NextSiblingElement("setting");
997 bool CGUIDialogAddonSettings::GetCondition(const CStdString &condition, const int controlId)
999 if (condition.empty()) return true;
1001 bool bCondition = true;
1002 bool bCompare = true;
1003 bool bControlDependend = false;//flag if the condition depends on another control
1004 vector<std::string> conditionVec;
1006 if (condition.find("+") != std::string::npos)
1007 StringUtils::Tokenize(condition, conditionVec, "+");
1012 StringUtils::Tokenize(condition, conditionVec, "|");
1015 for (unsigned int i = 0; i < conditionVec.size(); i++)
1017 vector<CStdString> condVec;
1018 if (!TranslateSingleString(conditionVec[i], condVec)) continue;
1020 const CGUIControl* control2 = GetControl(controlId + atoi(condVec[1]));
1024 bControlDependend = true; //once we are here - this condition depends on another control
1027 switch (control2->GetControlType())
1029 case CGUIControl::GUICONTROL_BUTTON:
1030 value = ((CGUIButtonControl*) control2)->GetLabel2();
1032 case CGUIControl::GUICONTROL_RADIO:
1033 value = ((CGUIRadioButtonControl*) control2)->IsSelected() ? "true" : "false";
1035 case CGUIControl::GUICONTROL_SPINEX:
1036 if (((CGUISpinControlEx*) control2)->GetFloatValue() > 0.0f)
1037 value = ((CGUISpinControlEx*) control2)->GetLabel();
1039 value = StringUtils::Format("%i", ((CGUISpinControlEx*) control2)->GetValue());
1045 if (condVec[0].Equals("eq"))
1048 bCondition &= value.Equals(condVec[2]);
1050 bCondition |= value.Equals(condVec[2]);
1052 else if (condVec[0].Equals("!eq"))
1055 bCondition &= !value.Equals(condVec[2]);
1057 bCondition |= !value.Equals(condVec[2]);
1059 else if (condVec[0].Equals("gt"))
1062 bCondition &= (atoi(value) > atoi(condVec[2]));
1064 bCondition |= (atoi(value) > atoi(condVec[2]));
1066 else if (condVec[0].Equals("lt"))
1069 bCondition &= (atoi(value) < atoi(condVec[2]));
1071 bCondition |= (atoi(value) < atoi(condVec[2]));
1075 if (!bControlDependend)//if condition doesn't depend on another control - try if its an infobool expression
1077 bCondition = g_infoManager.EvaluateBool(condition);
1083 bool CGUIDialogAddonSettings::TranslateSingleString(const CStdString &strCondition, vector<CStdString> &condVec)
1085 CStdString strTest = strCondition;
1086 StringUtils::ToLower(strTest);
1087 StringUtils::Trim(strTest);
1089 size_t pos1 = strTest.find("(");
1090 size_t pos2 = strTest.find(",", pos1);
1091 size_t pos3 = strTest.find(")", pos2);
1092 if (pos1 != std::string::npos &&
1093 pos2 != std::string::npos &&
1094 pos3 != std::string::npos)
1096 condVec.push_back(strTest.substr(0, pos1));
1097 condVec.push_back(strTest.substr(pos1 + 1, pos2 - pos1 - 1));
1098 condVec.push_back(strTest.substr(pos2 + 1, pos3 - pos2 - 1));
1104 CStdString CGUIDialogAddonSettings::GetString(const char *value, bool subSetting) const
1108 CStdString prefix(subSetting ? "- " : "");
1109 if (StringUtils::IsNaturalNumber(value))
1110 return prefix + m_addon->GetString(atoi(value));
1111 return prefix + value;
1114 // Go over all the settings and set their default values
1115 void CGUIDialogAddonSettings::SetDefaultSettings()
1120 const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category");
1121 if (!category) // add a default one...
1122 category = m_addon->GetSettingsXML();
1126 const TiXmlElement *setting = category->FirstChildElement("setting");
1129 const char *id = setting->Attribute("id");
1130 const char *type = setting->Attribute("type");
1131 const char *value = setting->Attribute("default");
1135 m_settings[id] = value;
1136 else if (type && 0 == strcmpi(type, "bool"))
1137 m_settings[id] = "false";
1138 else if (type && (0 == strcmpi(type, "slider") || 0 == strcmpi(type, "enum")))
1139 m_settings[id] = "0";
1141 m_settings[id] = "";
1143 setting = setting->NextSiblingElement("setting");
1145 category = category->NextSiblingElement("category");
1150 const TiXmlElement *CGUIDialogAddonSettings::GetFirstSetting() const
1152 const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category");
1154 category = m_addon->GetSettingsXML();
1155 for (unsigned int i = 0; i < m_currentSection && category; i++)
1156 category = category->NextSiblingElement("category");
1158 return category->FirstChildElement("setting");
1162 void CGUIDialogAddonSettings::DoProcess(unsigned int currentTime, CDirtyRegionList &dirtyregions)
1164 // update status of current section button
1165 bool alphaFaded = false;
1166 CGUIControl *control = GetFirstFocusableControl(CONTROL_START_SECTION + m_currentSection);
1167 if (control && !control->HasFocus())
1169 if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
1171 control->SetFocus(true);
1172 ((CGUIButtonControl *)control)->SetAlpha(0x80);
1175 else if (control->GetControlType() == CGUIControl::GUICONTROL_TOGGLEBUTTON)
1177 control->SetFocus(true);
1178 ((CGUIButtonControl *)control)->SetSelected(true);
1182 CGUIDialogBoxBase::DoProcess(currentTime, dirtyregions);
1183 if (alphaFaded && m_active) // dialog may close
1185 control->SetFocus(false);
1186 if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
1187 ((CGUIButtonControl *)control)->SetAlpha(0xFF);
1189 ((CGUIButtonControl *)control)->SetSelected(false);
1193 CStdString CGUIDialogAddonSettings::GetCurrentID() const
1196 return m_addon->ID();
1200 int CGUIDialogAddonSettings::GetDefaultLabelID(int controlId) const
1202 if (controlId == ID_BUTTON_OK)
1204 else if (controlId == ID_BUTTON_CANCEL)
1206 else if (controlId == ID_BUTTON_DEFAULT)
1209 return CGUIDialogBoxBase::GetDefaultLabelID(controlId);