From ffca21f2743a7b367fa212799c6e2fea6190dd5d Mon Sep 17 00:00:00 2001 From: manuel Date: Tue, 3 Mar 2015 16:53:59 +0100 Subject: initial commit for kodi master --- xbmc/addons/GUIDialogAddonSettings.cpp | 1200 ++++++++++++++++++++++++++++++++ 1 file changed, 1200 insertions(+) create mode 100644 xbmc/addons/GUIDialogAddonSettings.cpp (limited to 'xbmc/addons/GUIDialogAddonSettings.cpp') 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 @@ +/* + * Copyright (C) 2005-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 "GUIDialogAddonSettings.h" +#include "filesystem/PluginDirectory.h" +#include "addons/IAddon.h" +#include "addons/AddonManager.h" +#include "dialogs/GUIDialogNumeric.h" +#include "dialogs/GUIDialogFileBrowser.h" +#include "dialogs/GUIDialogOK.h" +#include "guilib/GUIControlGroupList.h" +#include "guilib/GUISettingsSliderControl.h" +#include "utils/URIUtils.h" +#include "utils/StringUtils.h" +#include "storage/MediaManager.h" +#include "guilib/GUILabelControl.h" +#include "guilib/GUIRadioButtonControl.h" +#include "guilib/GUISpinControlEx.h" +#include "guilib/GUIImage.h" +#include "input/Key.h" +#include "filesystem/Directory.h" +#include "video/VideoInfoScanner.h" +#include "addons/Scraper.h" +#include "guilib/GUIWindowManager.h" +#include "ApplicationMessenger.h" +#include "guilib/GUIKeyboardFactory.h" +#include "FileItem.h" +#include "settings/AdvancedSettings.h" +#include "settings/MediaSourceSettings.h" +#include "GUIInfoManager.h" +#include "GUIUserMessages.h" +#include "dialogs/GUIDialogSelect.h" +#include "GUIWindowAddonBrowser.h" +#include "utils/log.h" +#include "Util.h" +#include "URL.h" +#include "utils/XMLUtils.h" + +using namespace std; +using namespace ADDON; +using XFILE::CDirectory; + +#define CONTROL_SETTINGS_AREA 2 +#define CONTROL_DEFAULT_BUTTON 3 +#define CONTROL_DEFAULT_RADIOBUTTON 4 +#define CONTROL_DEFAULT_SPIN 5 +#define CONTROL_DEFAULT_SEPARATOR 6 +#define CONTROL_DEFAULT_LABEL_SEPARATOR 7 +#define CONTROL_DEFAULT_SLIDER 8 +#define CONTROL_SECTION_AREA 9 +#define CONTROL_DEFAULT_SECTION_BUTTON 13 + +#define ID_BUTTON_OK 10 +#define ID_BUTTON_CANCEL 11 +#define ID_BUTTON_DEFAULT 12 +#define CONTROL_HEADING_LABEL 20 + +#define CONTROL_START_SECTION 100 +#define CONTROL_START_SETTING 200 + +CGUIDialogAddonSettings::CGUIDialogAddonSettings() + : CGUIDialogBoxBase(WINDOW_DIALOG_ADDON_SETTINGS, "DialogAddonSettings.xml") +{ + m_currentSection = 0; + m_totalSections = 1; + m_saveToDisk = false; +} + +CGUIDialogAddonSettings::~CGUIDialogAddonSettings(void) +{ +} + +bool CGUIDialogAddonSettings::OnMessage(CGUIMessage& message) +{ + switch (message.GetMessage()) + { + case GUI_MSG_WINDOW_DEINIT: + { + FreeSections(); + } + break; + case GUI_MSG_CLICKED: + { + int iControl = message.GetSenderId(); + bool bCloseDialog = false; + + if (iControl == ID_BUTTON_DEFAULT) + SetDefaultSettings(); + else if (iControl != ID_BUTTON_OK) + bCloseDialog = ShowVirtualKeyboard(iControl); + + if (iControl == ID_BUTTON_OK || iControl == ID_BUTTON_CANCEL || bCloseDialog) + { + if (iControl == ID_BUTTON_OK || bCloseDialog) + { + m_bConfirmed = true; + SaveSettings(); + } + Close(); + return true; + } + } + break; + case GUI_MSG_FOCUSED: + { + CGUIDialogBoxBase::OnMessage(message); + int focusedControl = GetFocusedControlID(); + if (focusedControl >= CONTROL_START_SECTION && focusedControl < (int)(CONTROL_START_SECTION + m_totalSections) && + focusedControl - CONTROL_START_SECTION != (int)m_currentSection) + { // changing section + UpdateFromControls(); + m_currentSection = focusedControl - CONTROL_START_SECTION; + CreateControls(); + } + return true; + } + case GUI_MSG_SETTING_UPDATED: + { + std::string id = message.GetStringParam(0); + std::string value = message.GetStringParam(1); + m_settings[id] = value; + if (GetFocusedControl()) + { + int iControl = GetFocusedControl()->GetID(); + CreateControls(); + CGUIMessage msg(GUI_MSG_SETFOCUS,GetID(),iControl); + OnMessage(msg); + } + return true; + } + } + return CGUIDialogBoxBase::OnMessage(message); +} + +bool CGUIDialogAddonSettings::OnAction(const CAction& action) +{ + if (action.GetID() == ACTION_DELETE_ITEM) + { + CGUIControl* pControl = GetFocusedControl(); + if (pControl) + { + int iControl = pControl->GetID(); + int controlId = CONTROL_START_SETTING; + const TiXmlElement* setting = GetFirstSetting(); + UpdateFromControls(); + while (setting) + { + if (controlId == iControl) + { + const char* id = setting->Attribute("id"); + const char* value = setting->Attribute("default"); + if (id && value) + m_settings[id] = value; + CreateControls(); + CGUIMessage msg(GUI_MSG_SETFOCUS,GetID(),iControl); + OnMessage(msg); + return true; + } + setting = setting->NextSiblingElement("setting"); + controlId++; + } + } + } + return CGUIDialogBoxBase::OnAction(action); +} + +void CGUIDialogAddonSettings::OnInitWindow() +{ + m_currentSection = 0; + m_totalSections = 1; + CreateSections(); + CreateControls(); + CGUIDialogBoxBase::OnInitWindow(); +} + +// \brief Show CGUIDialogOK dialog, then wait for user to dismiss it. +bool CGUIDialogAddonSettings::ShowAndGetInput(const AddonPtr &addon, bool saveToDisk /* = true */) +{ + if (!addon) + return false; + + if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER)) + return false; + + bool ret(false); + if (addon->HasSettings()) + { + // Create the dialog + CGUIDialogAddonSettings* pDialog = NULL; + pDialog = (CGUIDialogAddonSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_ADDON_SETTINGS); + if (!pDialog) + return false; + + // Set the heading + std::string heading = StringUtils::Format("$LOCALIZE[10004] - %s", addon->Name().c_str()); // "Settings - AddonName" + pDialog->m_strHeading = heading; + + pDialog->m_addon = addon; + pDialog->m_saveToDisk = saveToDisk; + pDialog->DoModal(); + ret = true; + } + else + { // addon does not support settings, inform user + CGUIDialogOK::ShowAndGetInput(24000,0,24030,0); + } + + return ret; +} + +bool CGUIDialogAddonSettings::ShowVirtualKeyboard(int iControl) +{ + int controlId = CONTROL_START_SETTING; + bool bCloseDialog = false; + + const TiXmlElement *setting = GetFirstSetting(); + while (setting) + { + if (controlId == iControl) + { + const CGUIControl* control = GetControl(controlId); + const std::string id = XMLUtils::GetAttribute(setting, "id"); + const std::string type = XMLUtils::GetAttribute(setting, "type"); + + //Special handling for actions: does not require id attribute. TODO: refactor me. + if (control && control->GetControlType() == CGUIControl::GUICONTROL_BUTTON && type == "action") + { + const char *option = setting->Attribute("option"); + std::string action = XMLUtils::GetAttribute(setting, "action"); + if (!action.empty()) + { + // replace $CWD with the url of plugin/script + StringUtils::Replace(action, "$CWD", m_addon->Path()); + StringUtils::Replace(action, "$ID", m_addon->ID()); + if (option) + bCloseDialog = (strcmpi(option, "close") == 0); + CApplicationMessenger::Get().ExecBuiltIn(action); + } + break; + } + + if (control && control->GetControlType() == CGUIControl::GUICONTROL_BUTTON && + !id.empty() && !type.empty()) + { + const char *option = setting->Attribute("option"); + const char *source = setting->Attribute("source"); + std::string value = m_buttonValues[id]; + std::string label = GetString(setting->Attribute("label")); + + if (type == "text") + { + // get any options + bool bHidden = false; + bool bEncoded = false; + if (option) + { + bHidden = (strstr(option, "hidden") != NULL); + bEncoded = (strstr(option, "urlencoded") != NULL); + } + if (bEncoded) + value = CURL::Decode(value); + + if (CGUIKeyboardFactory::ShowAndGetInput(value, label, true, bHidden)) + { + // if hidden hide input + if (bHidden) + { + std::string hiddenText; + hiddenText.append(value.size(), L'*'); + ((CGUIButtonControl *)control)->SetLabel2(hiddenText); + } + else + ((CGUIButtonControl*) control)->SetLabel2(value); + if (bEncoded) + value = CURL::Encode(value); + } + } + else if (type == "number" && CGUIDialogNumeric::ShowAndGetNumber(value, label)) + { + ((CGUIButtonControl*) control)->SetLabel2(value); + } + else if (type == "ipaddress" && CGUIDialogNumeric::ShowAndGetIPAddress(value, label)) + { + ((CGUIButtonControl*) control)->SetLabel2(value); + } + else if (type == "select") + { + CGUIDialogSelect *pDlg = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); + if (pDlg) + { + pDlg->SetHeading(label.c_str()); + pDlg->Reset(); + + int selected = -1; + vector valuesVec; + if (setting->Attribute("values")) + StringUtils::Tokenize(setting->Attribute("values"), valuesVec, "|"); + else if (setting->Attribute("lvalues")) + { // localize + StringUtils::Tokenize(setting->Attribute("lvalues"), valuesVec, "|"); + for (unsigned int i = 0; i < valuesVec.size(); i++) + { + if (i == (unsigned int)atoi(value.c_str())) + selected = i; + std::string localized = m_addon->GetString(atoi(valuesVec[i].c_str())); + if (localized.empty()) + localized = g_localizeStrings.Get(atoi(valuesVec[i].c_str())); + valuesVec[i] = localized; + } + } + else if (source) + { + valuesVec = GetFileEnumValues(source, XMLUtils::GetAttribute(setting, "mask"), XMLUtils::GetAttribute(setting, "option")); + } + + for (unsigned int i = 0; i < valuesVec.size(); i++) + { + pDlg->Add(valuesVec[i]); + if (selected == (int)i || (selected < 0 && StringUtils::EqualsNoCase(valuesVec[i], value))) + pDlg->SetSelected(i); // FIXME: the SetSelected() does not select "i", it always defaults to the first position + } + pDlg->DoModal(); + int iSelected = pDlg->GetSelectedLabel(); + if (iSelected >= 0) + { + if (setting->Attribute("lvalues")) + value = StringUtils::Format("%i", iSelected); + else + value = valuesVec[iSelected]; + ((CGUIButtonControl*) control)->SetLabel2(valuesVec[iSelected]); + } + } + } + else if (type == "audio" || type == "video" + || type == "image" || type == "executable" + || type == "file" || type == "folder") + { + // setup the shares + VECSOURCES *shares = NULL; + if (source && strcmpi(source, "") != 0) + shares = CMediaSourceSettings::Get().GetSources(source); + + VECSOURCES localShares; + if (!shares) + { + g_mediaManager.GetLocalDrives(localShares); + if (!source || strcmpi(source, "local") != 0) + g_mediaManager.GetNetworkLocations(localShares); + } + else // always append local drives + { + localShares = *shares; + g_mediaManager.GetLocalDrives(localShares); + } + + if (type == "folder") + { + // get any options + bool bWriteOnly = false; + if (option) + bWriteOnly = (strcmpi(option, "writeable") == 0); + + if (CGUIDialogFileBrowser::ShowAndGetDirectory(localShares, label, value, bWriteOnly)) + ((CGUIButtonControl*) control)->SetLabel2(value); + } + else if (type == "image") + { + if (CGUIDialogFileBrowser::ShowAndGetImage(localShares, label, value)) + ((CGUIButtonControl*) control)->SetLabel2(value); + } + else + { + // set the proper mask + std::string strMask; + if (setting->Attribute("mask")) + { + strMask = setting->Attribute("mask"); + // convert mask qualifiers + StringUtils::Replace(strMask, "$AUDIO", g_advancedSettings.m_musicExtensions); + StringUtils::Replace(strMask, "$VIDEO", g_advancedSettings.m_videoExtensions); + StringUtils::Replace(strMask, "$IMAGE", g_advancedSettings.m_pictureExtensions); +#if defined(_WIN32_WINNT) + StringUtils::Replace(strMask, "$EXECUTABLE", ".exe|.bat|.cmd|.py"); +#else + StringUtils::Replace(strMask, "$EXECUTABLE", ""); +#endif + } + else + { + if (type == "video") + strMask = g_advancedSettings.m_videoExtensions; + else if (type == "audio") + strMask = g_advancedSettings.m_musicExtensions; + else if (type == "executable") +#if defined(_WIN32_WINNT) + strMask = ".exe|.bat|.cmd|.py"; +#else + strMask = ""; +#endif + } + + // get any options + bool bUseThumbs = false; + bool bUseFileDirectories = false; + if (option) + { + vector options = StringUtils::Split(option, '|'); + bUseThumbs = find(options.begin(), options.end(), "usethumbs") != options.end(); + bUseFileDirectories = find(options.begin(), options.end(), "treatasfolder") != options.end(); + } + + if (CGUIDialogFileBrowser::ShowAndGetFile(localShares, strMask, label, value, bUseThumbs, bUseFileDirectories)) + ((CGUIButtonControl*) control)->SetLabel2(value); + } + } + else if (type == "date") + { + CDateTime date; + if (!value.empty()) + date.SetFromDBDate(value); + SYSTEMTIME timedate; + date.GetAsSystemTime(timedate); + if(CGUIDialogNumeric::ShowAndGetDate(timedate, label)) + { + date = timedate; + value = date.GetAsDBDate(); + ((CGUIButtonControl*) control)->SetLabel2(value); + } + } + else if (type == "time") + { + SYSTEMTIME timedate; + if (value.size() >= 5) + { + // assumes HH:MM + timedate.wHour = atoi(value.substr(0, 2).c_str()); + timedate.wMinute = atoi(value.substr(3, 2).c_str()); + } + if (CGUIDialogNumeric::ShowAndGetTime(timedate, label)) + { + value = StringUtils::Format("%02d:%02d", timedate.wHour, timedate.wMinute); + ((CGUIButtonControl*) control)->SetLabel2(value); + } + } + else if (type == "addon") + { + const char *strType = setting->Attribute("addontype"); + if (strType) + { + vector addonTypes = StringUtils::Split(strType, ','); + vector types; + for (vector::iterator i = addonTypes.begin(); i != addonTypes.end(); ++i) + { + StringUtils::Trim(*i); + ADDON::TYPE type = TranslateType(*i); + if (type != ADDON_UNKNOWN) + types.push_back(type); + } + if (types.size() > 0) + { + const char *strMultiselect = setting->Attribute("multiselect"); + bool multiSelect = strMultiselect && strcmpi(strMultiselect, "true") == 0; + if (multiSelect) + { + // construct vector of addon IDs (IDs are comma seperated in single string) + vector addonIDs = StringUtils::Split(value, ','); + if (CGUIWindowAddonBrowser::SelectAddonID(types, addonIDs, false) == 1) + { + value = StringUtils::Join(addonIDs, ","); + ((CGUIButtonControl*) control)->SetLabel2(GetAddonNames(value)); + } + } + else // no need of string splitting/joining if we select only 1 addon + if (CGUIWindowAddonBrowser::SelectAddonID(types, value, false) == 1) + ((CGUIButtonControl*) control)->SetLabel2(GetAddonNames(value)); + } + } + } + m_buttonValues[id] = value; + break; + } + } + setting = setting->NextSiblingElement("setting"); + controlId++; + } + EnableControls(); + return bCloseDialog; +} + +void CGUIDialogAddonSettings::UpdateFromControls() +{ + int controlID = CONTROL_START_SETTING; + const TiXmlElement *setting = GetFirstSetting(); + while (setting) + { + const std::string id = XMLUtils::GetAttribute(setting, "id"); + const std::string type = XMLUtils::GetAttribute(setting, "type"); + const CGUIControl* control = GetControl(controlID++); + + if (control) + { + std::string value; + switch (control->GetControlType()) + { + case CGUIControl::GUICONTROL_BUTTON: + value = m_buttonValues[id]; + break; + case CGUIControl::GUICONTROL_RADIO: + value = ((CGUIRadioButtonControl*) control)->IsSelected() ? "true" : "false"; + break; + case CGUIControl::GUICONTROL_SPINEX: + if (type == "fileenum" || type == "labelenum") + value = ((CGUISpinControlEx*) control)->GetLabel(); + else + value = StringUtils::Format("%i", ((CGUISpinControlEx*) control)->GetValue()); + break; + case CGUIControl::GUICONTROL_SETTINGS_SLIDER: + { + std::string option = XMLUtils::GetAttribute(setting, "option"); + if (option.size() == 0 || StringUtils::EqualsNoCase(option, "float")) + value = StringUtils::Format("%f", ((CGUISettingsSliderControl *)control)->GetFloatValue()); + else + value = StringUtils::Format("%i", ((CGUISettingsSliderControl *)control)->GetIntValue()); + } + break; + default: + break; + } + m_settings[id] = value; + } + + setting = setting->NextSiblingElement("setting"); + } +} + +void CGUIDialogAddonSettings::SaveSettings(void) +{ + UpdateFromControls(); + + for (map::iterator i = m_settings.begin(); i != m_settings.end(); ++i) + m_addon->UpdateSetting(i->first, i->second); + + if (m_saveToDisk) + { + m_addon->SaveSettings(); + } +} + +void CGUIDialogAddonSettings::FreeSections() +{ + CGUIControlGroupList *group = dynamic_cast(GetControl(CONTROL_SECTION_AREA)); + if (group) + { + group->FreeResources(); + group->ClearAll(); + } + m_settings.clear(); + m_buttonValues.clear(); + FreeControls(); +} + +void CGUIDialogAddonSettings::FreeControls() +{ + // clear the category group + CGUIControlGroupList *control = dynamic_cast(GetControl(CONTROL_SETTINGS_AREA)); + if (control) + { + control->FreeResources(); + control->ClearAll(); + } +} + +void CGUIDialogAddonSettings::CreateSections() +{ + CGUIControlGroupList *group = dynamic_cast(GetControl(CONTROL_SECTION_AREA)); + CGUIButtonControl *originalButton = dynamic_cast(GetControl(CONTROL_DEFAULT_SECTION_BUTTON)); + if (!m_addon) + return; + + if (originalButton) + originalButton->SetVisible(false); + + // clear the category group + FreeSections(); + + // grab our categories + const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category"); + if (!category) // add a default one... + category = m_addon->GetSettingsXML(); + + int buttonID = CONTROL_START_SECTION; + while (category) + { // add a category + CGUIButtonControl *button = originalButton ? originalButton->Clone() : NULL; + + std::string label = GetString(category->Attribute("label")); + if (label.empty()) + label = g_localizeStrings.Get(128); + + if (buttonID >= CONTROL_START_SETTING) + { + CLog::Log(LOGERROR, "%s - cannot have more than %d categories - simplify your addon!", __FUNCTION__, CONTROL_START_SETTING - CONTROL_START_SECTION); + break; + } + + // add the category button + if (button && group) + { + button->SetID(buttonID++); + button->SetLabel(label); + button->SetVisible(true); + group->AddControl(button); + } + + // grab a local copy of all the settings in this category + const TiXmlElement *setting = category->FirstChildElement("setting"); + while (setting) + { + const std::string id = XMLUtils::GetAttribute(setting, "id"); + if (!id.empty()) + m_settings[id] = m_addon->GetSetting(id); + setting = setting->NextSiblingElement("setting"); + } + category = category->NextSiblingElement("category"); + } + m_totalSections = buttonID - CONTROL_START_SECTION; +} + +void CGUIDialogAddonSettings::CreateControls() +{ + FreeControls(); + + CGUISpinControlEx *pOriginalSpin = dynamic_cast(GetControl(CONTROL_DEFAULT_SPIN)); + CGUIRadioButtonControl *pOriginalRadioButton = dynamic_cast(GetControl(CONTROL_DEFAULT_RADIOBUTTON)); + CGUIButtonControl *pOriginalButton = dynamic_cast(GetControl(CONTROL_DEFAULT_BUTTON)); + CGUIImage *pOriginalImage = dynamic_cast(GetControl(CONTROL_DEFAULT_SEPARATOR)); + CGUILabelControl *pOriginalLabel = dynamic_cast(GetControl(CONTROL_DEFAULT_LABEL_SEPARATOR)); + CGUISettingsSliderControl *pOriginalSlider = dynamic_cast(GetControl(CONTROL_DEFAULT_SLIDER)); + + if (!m_addon || !pOriginalSpin || !pOriginalRadioButton || !pOriginalButton || !pOriginalImage + || !pOriginalLabel || !pOriginalSlider) + return; + + pOriginalSpin->SetVisible(false); + pOriginalRadioButton->SetVisible(false); + pOriginalButton->SetVisible(false); + pOriginalImage->SetVisible(false); + pOriginalLabel->SetVisible(false); + pOriginalSlider->SetVisible(false); + + CGUIControlGroupList *group = dynamic_cast(GetControl(CONTROL_SETTINGS_AREA)); + if (!group) + return; + + // set our dialog heading + SET_CONTROL_LABEL(CONTROL_HEADING_LABEL, m_strHeading); + + CGUIControl* pControl = NULL; + int controlId = CONTROL_START_SETTING; + const TiXmlElement *setting = GetFirstSetting(); + while (setting) + { + const std::string type = XMLUtils::GetAttribute(setting, "type"); + const std::string id = XMLUtils::GetAttribute(setting, "id"); + const std::string values = XMLUtils::GetAttribute(setting, "values"); + const std::string lvalues = XMLUtils::GetAttribute(setting, "lvalues"); + const std::string entries = XMLUtils::GetAttribute(setting, "entries"); + const std::string defaultVal = XMLUtils::GetAttribute(setting, "default"); + const std::string subsetting = XMLUtils::GetAttribute(setting, "subsetting"); + const std::string label = GetString(setting->Attribute("label"), subsetting == "true"); + + bool bSort = XMLUtils::GetAttribute(setting, "sort") == "yes"; + if (!type.empty()) + { + bool isAddonSetting = false; + if (type == "text" || type == "ipaddress" + || type == "number" || type == "video" + || type == "audio" || type == "image" + || type == "folder" || type == "executable" + || type == "file" || type == "action" + || type == "date" || type == "time" + || type == "select" || (isAddonSetting = type == "addon")) + { + pControl = new CGUIButtonControl(*pOriginalButton); + if (!pControl) return; + ((CGUIButtonControl *)pControl)->SetLabel(label); + if (!id.empty()) + { + std::string value = m_settings[id]; + m_buttonValues[id] = value; + // get any option to test for hidden + const std::string option = XMLUtils::GetAttribute(setting, "option"); + if (option == "urlencoded") + value = CURL::Decode(value); + else if (option == "hidden") + { + std::string hiddenText; + hiddenText.append(value.size(), L'*'); + ((CGUIButtonControl *)pControl)->SetLabel2(hiddenText); + } + else + { + if (isAddonSetting) + ((CGUIButtonControl *)pControl)->SetLabel2(GetAddonNames(value)); + else if (type == "select" && !lvalues.empty()) + { + vector valuesVec = StringUtils::Split(lvalues, '|'); + int selected = atoi(value.c_str()); + if (selected >= 0 && selected < (int)valuesVec.size()) + { + std::string label = m_addon->GetString(atoi(valuesVec[selected].c_str())); + if (label.empty()) + label = g_localizeStrings.Get(atoi(valuesVec[selected].c_str())); + ((CGUIButtonControl *)pControl)->SetLabel2(label); + } + } + else + ((CGUIButtonControl *)pControl)->SetLabel2(value); + } + } + else + ((CGUIButtonControl *)pControl)->SetLabel2(defaultVal); + } + else if (type == "bool" && !id.empty()) + { + pControl = new CGUIRadioButtonControl(*pOriginalRadioButton); + if (!pControl) return; + ((CGUIRadioButtonControl *)pControl)->SetLabel(label); + ((CGUIRadioButtonControl *)pControl)->SetSelected(m_settings[id] == "true"); + } + else if ((type == "enum" || type == "labelenum") && !id.empty()) + { + vector valuesVec; + vector entryVec; + + pControl = new CGUISpinControlEx(*pOriginalSpin); + if (!pControl) return; + ((CGUISpinControlEx *)pControl)->SetText(label); + + if (!lvalues.empty()) + StringUtils::Tokenize(lvalues, valuesVec, "|"); + else if (values == "$HOURS") + { + for (unsigned int i = 0; i < 24; i++) + { + CDateTime time(2000, 1, 1, i, 0, 0); + valuesVec.push_back(g_infoManager.LocalizeTime(time, TIME_FORMAT_HH_MM_XX)); + } + } + else + StringUtils::Tokenize(values, valuesVec, "|"); + if (!entries.empty()) + StringUtils::Tokenize(entries, entryVec, "|"); + + if(bSort && type == "labelenum") + std::sort(valuesVec.begin(), valuesVec.end(), sortstringbyname()); + + for (unsigned int i = 0; i < valuesVec.size(); i++) + { + int iAdd = i; + if (entryVec.size() > i) + iAdd = atoi(entryVec[i].c_str()); + if (!lvalues.empty()) + { + std::string replace = m_addon->GetString(atoi(valuesVec[i].c_str())); + if (replace.empty()) + replace = g_localizeStrings.Get(atoi(valuesVec[i].c_str())); + ((CGUISpinControlEx *)pControl)->AddLabel(replace, iAdd); + } + else + ((CGUISpinControlEx *)pControl)->AddLabel(valuesVec[i], iAdd); + } + if (type == "labelenum") + { // need to run through all our settings and find the one that matches + ((CGUISpinControlEx*) pControl)->SetValueFromLabel(m_settings[id]); + } + else + ((CGUISpinControlEx*) pControl)->SetValue(atoi(m_settings[id].c_str())); + + } + else if (type == "fileenum" && !id.empty()) + { + pControl = new CGUISpinControlEx(*pOriginalSpin); + if (!pControl) return; + ((CGUISpinControlEx *)pControl)->SetText(label); + ((CGUISpinControlEx *)pControl)->SetFloatValue(1.0f); + + vector items = GetFileEnumValues(values, XMLUtils::GetAttribute(setting, "mask"), XMLUtils::GetAttribute(setting, "option")); + for (unsigned int i = 0; i < items.size(); ++i) + { + ((CGUISpinControlEx *)pControl)->AddLabel(items[i], i); + if (StringUtils::EqualsNoCase(items[i], m_settings[id])) + ((CGUISpinControlEx *)pControl)->SetValue(i); + } + } + // Sample: + // in strings.xml: %2.0f mp + // creates 11 piece, text formated number labels from 0 to 100 + else if (type == "rangeofnum" && !id.empty()) + { + pControl = new CGUISpinControlEx(*pOriginalSpin); + if (!pControl) + return; + ((CGUISpinControlEx *)pControl)->SetText(label); + ((CGUISpinControlEx *)pControl)->SetFloatValue(1.0f); + + double rangestart = 0, rangeend = 1; + setting->Attribute("rangestart", &rangestart); + setting->Attribute("rangeend", &rangeend); + + int elements = 2; + setting->Attribute("elements", &elements); + + std::string valueformat; + if (setting->Attribute("valueformat")) + valueformat = m_addon->GetString(atoi(setting->Attribute("valueformat"))); + for (int i = 0; i < elements; i++) + { + std::string valuestring; + if (elements < 2) + valuestring = StringUtils::Format(valueformat.c_str(), rangestart); + else + valuestring = StringUtils::Format(valueformat.c_str(), rangestart+(rangeend-rangestart)/(elements-1)*i); + ((CGUISpinControlEx *)pControl)->AddLabel(valuestring, i); + } + ((CGUISpinControlEx *)pControl)->SetValue(atoi(m_settings[id].c_str())); + } + // Sample: + // to make ints from 5-60 with 5 steps + else if (type == "slider" && !id.empty()) + { + pControl = new CGUISettingsSliderControl(*pOriginalSlider); + if (!pControl) return; + ((CGUISettingsSliderControl *)pControl)->SetText(label); + + float fMin = 0.0f; + float fMax = 100.0f; + float fInc = 1.0f; + vector range = StringUtils::Split(XMLUtils::GetAttribute(setting, "range"), ','); + if (range.size() > 1) + { + fMin = (float)atof(range[0].c_str()); + if (range.size() > 2) + { + fMax = (float)atof(range[2].c_str()); + fInc = (float)atof(range[1].c_str()); + } + else + fMax = (float)atof(range[1].c_str()); + } + + std::string option = XMLUtils::GetAttribute(setting, "option"); + int iType=0; + + if (option.empty() || StringUtils::EqualsNoCase(option, "float")) + iType = SLIDER_CONTROL_TYPE_FLOAT; + else if (StringUtils::EqualsNoCase(option, "int")) + iType = SLIDER_CONTROL_TYPE_INT; + else if (StringUtils::EqualsNoCase(option, "percent")) + iType = SLIDER_CONTROL_TYPE_PERCENTAGE; + + ((CGUISettingsSliderControl *)pControl)->SetType(iType); + ((CGUISettingsSliderControl *)pControl)->SetFloatRange(fMin, fMax); + ((CGUISettingsSliderControl *)pControl)->SetFloatInterval(fInc); + ((CGUISettingsSliderControl *)pControl)->SetFloatValue((float)atof(m_settings[id].c_str())); + } + else if (type == "lsep") + { + pControl = new CGUILabelControl(*pOriginalLabel); + if (pControl) + ((CGUILabelControl *)pControl)->SetLabel(label); + } + else if (type == "sep") + pControl = new CGUIImage(*pOriginalImage); + } + + if (pControl) + { + pControl->SetWidth(group->GetWidth()); + pControl->SetVisible(true); + pControl->SetID(controlId); + pControl->AllocResources(); + group->AddControl(pControl); + pControl = NULL; + } + + setting = setting->NextSiblingElement("setting"); + controlId++; + } + EnableControls(); +} + +std::string CGUIDialogAddonSettings::GetAddonNames(const std::string& addonIDslist) const +{ + std::string retVal; + vector addons = StringUtils::Split(addonIDslist, ','); + for (vector::const_iterator it = addons.begin(); it != addons.end() ; ++it) + { + if (!retVal.empty()) + retVal += ", "; + AddonPtr addon; + if (CAddonMgr::Get().GetAddon(*it ,addon)) + retVal += addon->Name(); + else + retVal += *it; + } + return retVal; +} + +vector CGUIDialogAddonSettings::GetFileEnumValues(const std::string &path, const std::string &mask, const std::string &options) const +{ + // Create our base path, used for type "fileenum" settings + // replace $PROFILE with the profile path of the plugin/script + std::string fullPath = path; + if (fullPath.find("$PROFILE") != std::string::npos) + StringUtils::Replace(fullPath, "$PROFILE", m_addon->Profile()); + else + fullPath = URIUtils::AddFileToFolder(m_addon->Path(), path); + + bool hideExtensions = StringUtils::EqualsNoCase(options, "hideext"); + // fetch directory + CFileItemList items; + if (!mask.empty()) + CDirectory::GetDirectory(fullPath, items, mask, XFILE::DIR_FLAG_NO_FILE_DIRS); + else + CDirectory::GetDirectory(fullPath, items, "", XFILE::DIR_FLAG_NO_FILE_DIRS); + + vector values; + for (int i = 0; i < items.Size(); ++i) + { + CFileItemPtr pItem = items[i]; + if ((mask == "/" && pItem->m_bIsFolder) || !pItem->m_bIsFolder) + { + if (hideExtensions) + pItem->RemoveExtension(); + values.push_back(pItem->GetLabel()); + } + } + return values; +} + +// Go over all the settings and set their enabled condition according to the values of the enabled attribute +void CGUIDialogAddonSettings::EnableControls() +{ + int controlId = CONTROL_START_SETTING; + const TiXmlElement *setting = GetFirstSetting(); + while (setting) + { + const CGUIControl* control = GetControl(controlId); + if (control) + { + // set enable status + const char *enable = setting->Attribute("enable"); + if (enable) + ((CGUIControl*) control)->SetEnabled(GetCondition(enable, controlId)); + else + ((CGUIControl*) control)->SetEnabled(true); + // set visible status + const char *visible = setting->Attribute("visible"); + if (visible) + ((CGUIControl*) control)->SetVisible(GetCondition(visible, controlId)); + else + ((CGUIControl*) control)->SetVisible(true); + } + setting = setting->NextSiblingElement("setting"); + controlId++; + } +} + +bool CGUIDialogAddonSettings::GetCondition(const std::string &condition, const int controlId) +{ + if (condition.empty()) return true; + + bool bCondition = true; + bool bCompare = true; + bool bControlDependend = false;//flag if the condition depends on another control + vector conditionVec; + + if (condition.find("+") != std::string::npos) + StringUtils::Tokenize(condition, conditionVec, "+"); + else + { + bCondition = false; + bCompare = false; + StringUtils::Tokenize(condition, conditionVec, "|"); + } + + for (unsigned int i = 0; i < conditionVec.size(); i++) + { + vector condVec; + if (!TranslateSingleString(conditionVec[i], condVec)) continue; + + const CGUIControl* control2 = GetControl(controlId + atoi(condVec[1].c_str())); + if (!control2) + continue; + + bControlDependend = true; //once we are here - this condition depends on another control + + std::string value; + switch (control2->GetControlType()) + { + case CGUIControl::GUICONTROL_BUTTON: + value = ((CGUIButtonControl*) control2)->GetLabel2(); + break; + case CGUIControl::GUICONTROL_RADIO: + value = ((CGUIRadioButtonControl*) control2)->IsSelected() ? "true" : "false"; + break; + case CGUIControl::GUICONTROL_SPINEX: + if (((CGUISpinControlEx*) control2)->GetFloatValue() > 0.0f) + value = ((CGUISpinControlEx*) control2)->GetLabel(); + else + value = StringUtils::Format("%i", ((CGUISpinControlEx*) control2)->GetValue()); + break; + default: + break; + } + + if (condVec[0] == "eq") + { + if (bCompare) + bCondition &= StringUtils::EqualsNoCase(value, condVec[2]); + else + bCondition |= StringUtils::EqualsNoCase(value, condVec[2]); + } + else if (condVec[0] == "!eq") + { + if (bCompare) + bCondition &= !StringUtils::EqualsNoCase(value, condVec[2]); + else + bCondition |= !StringUtils::EqualsNoCase(value, condVec[2]); + } + else if (condVec[0] == "gt") + { + if (bCompare) + bCondition &= (atoi(value.c_str()) > atoi(condVec[2].c_str())); + else + bCondition |= (atoi(value.c_str()) > atoi(condVec[2].c_str())); + } + else if (condVec[0] == "lt") + { + if (bCompare) + bCondition &= (atoi(value.c_str()) < atoi(condVec[2].c_str())); + else + bCondition |= (atoi(value.c_str()) < atoi(condVec[2].c_str())); + } + } + + if (!bControlDependend)//if condition doesn't depend on another control - try if its an infobool expression + { + bCondition = g_infoManager.EvaluateBool(condition); + } + + return bCondition; +} + +bool CGUIDialogAddonSettings::TranslateSingleString(const std::string &strCondition, vector &condVec) +{ + std::string strTest = strCondition; + StringUtils::ToLower(strTest); + StringUtils::Trim(strTest); + + size_t pos1 = strTest.find("("); + size_t pos2 = strTest.find(",", pos1); + size_t pos3 = strTest.find(")", pos2); + if (pos1 != std::string::npos && + pos2 != std::string::npos && + pos3 != std::string::npos) + { + condVec.push_back(strTest.substr(0, pos1)); + condVec.push_back(strTest.substr(pos1 + 1, pos2 - pos1 - 1)); + condVec.push_back(strTest.substr(pos2 + 1, pos3 - pos2 - 1)); + return true; + } + return false; +} + +std::string CGUIDialogAddonSettings::GetString(const char *value, bool subSetting) const +{ + if (!value) + return ""; + std::string prefix(subSetting ? "- " : ""); + if (StringUtils::IsNaturalNumber(value)) + return prefix + m_addon->GetString(atoi(value)); + return prefix + value; +} + +// Go over all the settings and set their default values +void CGUIDialogAddonSettings::SetDefaultSettings() +{ + if(!m_addon) + return; + + const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category"); + if (!category) // add a default one... + category = m_addon->GetSettingsXML(); + + while (category) + { + const TiXmlElement *setting = category->FirstChildElement("setting"); + while (setting) + { + const std::string id = XMLUtils::GetAttribute(setting, "id"); + const std::string type = XMLUtils::GetAttribute(setting, "type"); + const char *value = setting->Attribute("default"); + if (!id.empty()) + { + if (value) + m_settings[id] = value; + else if (type == "bool") + m_settings[id] = "false"; + else if (type == "slider" || type == "enum") + m_settings[id] = "0"; + else + m_settings[id] = ""; + } + setting = setting->NextSiblingElement("setting"); + } + category = category->NextSiblingElement("category"); + } + CreateControls(); +} + +const TiXmlElement *CGUIDialogAddonSettings::GetFirstSetting() const +{ + const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category"); + if (!category) + category = m_addon->GetSettingsXML(); + for (unsigned int i = 0; i < m_currentSection && category; i++) + category = category->NextSiblingElement("category"); + if (category) + return category->FirstChildElement("setting"); + return NULL; +} + +void CGUIDialogAddonSettings::DoProcess(unsigned int currentTime, CDirtyRegionList &dirtyregions) +{ + // update status of current section button + bool alphaFaded = false; + CGUIControl *control = GetFirstFocusableControl(CONTROL_START_SECTION + m_currentSection); + if (control && !control->HasFocus()) + { + if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON) + { + control->SetFocus(true); + ((CGUIButtonControl *)control)->SetAlpha(0x80); + alphaFaded = true; + } + else if (control->GetControlType() == CGUIControl::GUICONTROL_TOGGLEBUTTON) + { + control->SetFocus(true); + ((CGUIButtonControl *)control)->SetSelected(true); + alphaFaded = true; + } + } + CGUIDialogBoxBase::DoProcess(currentTime, dirtyregions); + if (alphaFaded && m_active) // dialog may close + { + control->SetFocus(false); + if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON) + ((CGUIButtonControl *)control)->SetAlpha(0xFF); + else + ((CGUIButtonControl *)control)->SetSelected(false); + } +} + +std::string CGUIDialogAddonSettings::GetCurrentID() const +{ + if (m_addon) + return m_addon->ID(); + return ""; +} + +int CGUIDialogAddonSettings::GetDefaultLabelID(int controlId) const +{ + if (controlId == ID_BUTTON_OK) + return 186; + else if (controlId == ID_BUTTON_CANCEL) + return 222; + else if (controlId == ID_BUTTON_DEFAULT) + return 409; + + return CGUIDialogBoxBase::GetDefaultLabelID(controlId); +} -- cgit v1.2.3