Index: guilib/Key.h =================================================================== --- guilib/Key.h (revision 30503) +++ guilib/Key.h (working copy) @@ -345,6 +345,7 @@ #define WINDOW_DIALOG_PLUGIN_SETTINGS 10140 #define WINDOW_DIALOG_FULLSCREEN_INFO 10142 #define WINDOW_DIALOG_SLIDER 10145 +#define WINDOW_DIALOG_TEXT_VIEWER 10147 #define WINDOW_MUSIC_PLAYLIST 10500 #define WINDOW_MUSIC_FILES 10501 Index: guilib/SkinInfo.cpp =================================================================== --- guilib/SkinInfo.cpp (revision 30503) +++ guilib/SkinInfo.cpp (working copy) @@ -198,7 +198,8 @@ if (!strBaseDir.IsEmpty()) strPathToUse = strBaseDir; // first try and load from the current resolution's directory - *res = g_graphicsContext.GetVideoResolution(); + if (!res) + *res = g_graphicsContext.GetVideoResolution(); CStdString strPath = CUtil::AddFileToFolder(strPathToUse, GetDirFromRes(*res)); strPath = CUtil::AddFileToFolder(strPath, strFile); if (CFile::Exists(strPath)) @@ -269,6 +270,24 @@ return strRes; } +RESOLUTION CSkinInfo::TranslateResolution(const CStdString &res, RESOLUTION def) +{ + if (res.Equals("pal")) + return PAL_4x3; + else if (res.Equals("pal16x9")) + return PAL_16x9; + else if (res.Equals("ntsc")) + return NTSC_4x3; + else if (res.Equals("ntsc16x9")) + return NTSC_16x9; + else if (res.Equals("720p")) + return HDTV_720p; + else if (res.Equals("1080i")) + return HDTV_1080i; + CLog::Log(LOGERROR, "%s invalid resolution specified for %s", __FUNCTION__, res.c_str()); + return def; +} + CStdString CSkinInfo::GetBaseDir() { return m_strBaseDir; Index: guilib/SkinInfo.h =================================================================== --- guilib/SkinInfo.h (revision 30503) +++ guilib/SkinInfo.h (working copy) @@ -51,6 +51,12 @@ wchar_t* GetCreditsLine(int i); CStdString GetDirFromRes(RESOLUTION res); + /*! \brief Translate a resolution string + \param res the string to translate + \param def the default to use if res is invalid + \return the translated resolution + */ + static RESOLUTION TranslateResolution(const CStdString &res, RESOLUTION def); CStdString GetBaseDir(); double GetMinVersion(); double GetVersion(){ return m_Version;}; Index: xbmc.vcproj =================================================================== --- xbmc.vcproj (revision 30503) +++ xbmc.vcproj (working copy) @@ -1350,6 +1350,12 @@ RelativePath=".\xbmc\GUIDialogSubMenu.cpp"> + + + + = 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; + } } return CGUIDialogBoxBase::OnMessage(message); } void CGUIDialogPluginSettings::OnInitWindow() { - FreeControls(); + m_currentSection = 0; + m_totalSections = 1; + CreateSections(); CreateControls(); CGUIDialogBoxBase::OnInitWindow(); - m_bConfirmed = false; } // \brief Show CGUIDialogOK dialog, then wait for user to dismiss it. -bool CGUIDialogPluginSettings::ShowAndGetInput(CURL& url) +bool CGUIDialogPluginSettings::ShowAndGetInput(CURL& url, bool saveToDisk /* = true */) { - m_url = url; - - // Load language strings temporarily - DIRECTORY::CPluginDirectory::LoadPluginStrings(url); - - // Create the dialog - CGUIDialogPluginSettings* pDialog = (CGUIDialogPluginSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_PLUGIN_SETTINGS); - - pDialog->m_strHeading = m_url.GetFileName(); - CUtil::RemoveSlashAtEnd(pDialog->m_strHeading); - pDialog->m_strHeading.Format("$LOCALIZE[1045] - %s", pDialog->m_strHeading.c_str()); - CPluginSettings settings; - settings.Load(m_url); - pDialog->m_settings = settings; + if (settings.Load(url)) + { + // Create the dialog + CGUIDialogPluginSettings* pDialog = NULL; + pDialog = (CGUIDialogPluginSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_PLUGIN_SETTINGS); + if (!pDialog) + return false; - pDialog->DoModal(); + // Load language strings temporarily + DIRECTORY::CPluginDirectory::LoadPluginStrings(url); - if(pDialog->m_bConfirmed) - { - settings = pDialog->m_settings; - settings.Save(); + pDialog->m_url = url; + pDialog->m_strHeading = pDialog->m_url.GetFileNameWithoutPath(); + CUtil::RemoveSlashAtEnd(pDialog->m_strHeading); + pDialog->m_profile.Format("special://profile/plugin_data/%s/%s", pDialog->m_url.GetHostName().c_str(), pDialog->m_strHeading.c_str()); + pDialog->m_strHeading.Format("$LOCALIZE[1045] - %s", pDialog->m_strHeading.c_str()); + pDialog->m_addon = settings; + pDialog->m_changed = false; + pDialog->m_saveToDisk = saveToDisk; + pDialog->DoModal(); + if(pDialog->m_bConfirmed) + { + settings = pDialog->m_addon; + settings.Save(); + } + return pDialog->m_bConfirmed; } - - return pDialog->m_bConfirmed; + return false; } // \brief Show CGUIDialogOK dialog, then wait for user to dismiss it. -bool CGUIDialogPluginSettings::ShowAndGetInput(SScraperInfo& info) +bool CGUIDialogPluginSettings::ShowAndGetInput(SScraperInfo& info, bool saveToDisk /* = true */) { // Create the dialog - CGUIDialogPluginSettings* pDialog = (CGUIDialogPluginSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_PLUGIN_SETTINGS); + CGUIDialogPluginSettings* pDialog = NULL; + pDialog = (CGUIDialogPluginSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_PLUGIN_SETTINGS); + if (!pDialog) + return false; - pDialog->m_settings = info.settings; + pDialog->m_addon = info.settings; pDialog->m_strHeading.Format("$LOCALIZE[20407] - %s", info.strTitle.c_str()); - + pDialog->m_profile = ""; + pDialog->m_changed = false; + pDialog->m_saveToDisk = saveToDisk; pDialog->DoModal(); if(pDialog->m_bConfirmed) - info.settings.LoadUserXML(static_cast(pDialog->m_settings).GetSettings()); + info.settings.LoadUserXML(static_cast(pDialog->m_addon).GetSettings()); return pDialog->m_bConfirmed; } // \brief Show CGUIDialogOK dialog, then wait for user to dismiss it. -bool CGUIDialogPluginSettings::ShowAndGetInput(CStdString& path) +bool CGUIDialogPluginSettings::ShowAndGetInput(CStdString& path, bool saveToDisk /* = true */) { CUtil::RemoveSlashAtEnd(path); - m_url = CURL(path); + CScriptSettings settings; + if (settings.Load(path)) + { + // Create the dialog + CGUIDialogPluginSettings* pDialog = NULL; + pDialog = (CGUIDialogPluginSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_PLUGIN_SETTINGS); + if (!pDialog) + return false; - // Path where the language strings reside - CStdString pathToLanguageFile = path; - CStdString pathToFallbackLanguageFile = path; - CUtil::AddFileToFolder(pathToLanguageFile, "resources", pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "resources", pathToFallbackLanguageFile); - CUtil::AddFileToFolder(pathToLanguageFile, "language", pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "language", pathToFallbackLanguageFile); - CUtil::AddFileToFolder(pathToLanguageFile, g_guiSettings.GetString("locale.language"), pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "english", pathToFallbackLanguageFile); - CUtil::AddFileToFolder(pathToLanguageFile, "strings.xml", pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "strings.xml", pathToFallbackLanguageFile); + pDialog->m_url = CURL(path); - // Load language strings temporarily - g_localizeStringsTemp.Load(pathToLanguageFile, pathToFallbackLanguageFile); + // Path where the language strings reside + CStdString pathToLanguageFile = path; + CStdString pathToFallbackLanguageFile = path; + CUtil::AddFileToFolder(pathToLanguageFile, "resources", pathToLanguageFile); + CUtil::AddFileToFolder(pathToFallbackLanguageFile, "resources", pathToFallbackLanguageFile); + CUtil::AddFileToFolder(pathToLanguageFile, "language", pathToLanguageFile); + CUtil::AddFileToFolder(pathToFallbackLanguageFile, "language", pathToFallbackLanguageFile); + CUtil::AddFileToFolder(pathToLanguageFile, g_guiSettings.GetString("locale.language"), pathToLanguageFile); + CUtil::AddFileToFolder(pathToFallbackLanguageFile, "english", pathToFallbackLanguageFile); + CUtil::AddFileToFolder(pathToLanguageFile, "strings.xml", pathToLanguageFile); + CUtil::AddFileToFolder(pathToFallbackLanguageFile, "strings.xml", pathToFallbackLanguageFile); + // Load language strings temporarily + g_localizeStringsTemp.Load(pathToLanguageFile, pathToFallbackLanguageFile); - // Create the dialog - CGUIDialogPluginSettings* pDialog = (CGUIDialogPluginSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_PLUGIN_SETTINGS); - - pDialog->m_strHeading = CUtil::GetFileName(path); - pDialog->m_strHeading.Format("$LOCALIZE[1049] - %s", pDialog->m_strHeading.c_str()); - - CScriptSettings settings; - settings.Load(path); - pDialog->m_settings = settings; - - pDialog->DoModal(); - - if(pDialog->m_bConfirmed) - { - settings = pDialog->m_settings; - settings.Save(); + pDialog->m_strHeading = pDialog->m_url.GetFileNameWithoutPath(); + CUtil::RemoveSlashAtEnd(pDialog->m_strHeading); + pDialog->m_profile.Format("special://profile/script_data/%s", pDialog->m_strHeading.c_str()); + pDialog->m_strHeading.Format("$LOCALIZE[1049] - %s", pDialog->m_strHeading.c_str()); + pDialog->m_addon = settings; + pDialog->m_changed = false; + pDialog->m_saveToDisk = saveToDisk; + pDialog->DoModal(); + if(pDialog->m_bConfirmed) + { + settings = pDialog->m_addon; + settings.Save(); + } + return pDialog->m_bConfirmed; } - - return pDialog->m_bConfirmed; + return false; } bool CGUIDialogPluginSettings::ShowVirtualKeyboard(int iControl) { - int controlId = CONTROL_START_CONTROL; + int controlId = CONTROL_START_SETTING; bool bCloseDialog = false; - TiXmlElement *setting = m_settings.GetPluginRoot()->FirstChildElement("setting"); + const TiXmlElement *setting = GetFirstSetting(); + while (setting) { if (controlId == iControl) @@ -206,11 +254,12 @@ const char *option = setting->Attribute("option"); const char *source = setting->Attribute("source"); CStdString value = m_buttonValues[id]; + CStdString label = GetString(setting->Attribute("label")); if (strcmp(type, "text") == 0) { // get any options - bool bHidden = false; + bool bHidden = false; bool bEncoded = false; if (option) { @@ -220,7 +269,7 @@ if (bEncoded) CUtil::URLDecode(value); - if (CGUIDialogKeyboard::ShowAndGetInput(value, ((CGUIButtonControl*) control)->GetLabel(), true, bHidden)) + if (CGUIDialogKeyboard::ShowAndGetInput(value, label, true, bHidden)) { // if hidden hide input if (bHidden) @@ -235,18 +284,60 @@ CUtil::URLEncode(value); } } - else if (strcmp(type, "integer") == 0 && CGUIDialogNumeric::ShowAndGetNumber(value, ((CGUIButtonControl*) control)->GetLabel())) + else if (strcmp(type, "number") == 0 && CGUIDialogNumeric::ShowAndGetNumber(value, label)) { ((CGUIButtonControl*) control)->SetLabel2(value); } - else if (strcmp(type, "ipaddress") == 0 && CGUIDialogNumeric::ShowAndGetIPAddress(value, ((CGUIButtonControl*) control)->GetLabel())) + else if (strcmp(type, "ipaddress") == 0 && CGUIDialogNumeric::ShowAndGetIPAddress(value, label)) { ((CGUIButtonControl*) control)->SetLabel2(value); } - else if (strcmpi(type, "video") == 0 || strcmpi(type, "music") == 0 || - strcmpi(type, "pictures") == 0 || strcmpi(type, "programs") == 0 || - strcmpi(type, "folder") == 0 || strcmpi(type, "files") == 0) + else if (strcmpi(type, "select") == 0) { + CGUIDialogSelect *pDlg = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); + if (pDlg) + { + pDlg->SetHeading(label.c_str()); + pDlg->Reset(); + + vector valuesVec; + if (setting->Attribute("values")) + CUtil::Tokenize(setting->Attribute("values"), valuesVec, "|"); + else if (setting->Attribute("lvalues")) + { // localize + CUtil::Tokenize(setting->Attribute("lvalues"), valuesVec, "|"); + for (unsigned int i = 0; i < valuesVec.size(); i++) + { + CStdString value = g_localizeStringsTemp.Get(atoi(valuesVec[i])); + if (value.IsEmpty()) + value = g_localizeStrings.Get(atoi(valuesVec[i])); + valuesVec[i] = value; + } + } + else if (source) + { + valuesVec = GetFileEnumValues(source, setting->Attribute("mask"), setting->Attribute("option")); + } + + for (unsigned int i = 0; i < valuesVec.size(); i++) + { + pDlg->Add(valuesVec[i]); + if (valuesVec[i].Equals(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) + { + value = valuesVec[iSelected]; + ((CGUIButtonControl*) control)->SetLabel2(value); + } + } + } + else if (strcmpi(type, "audio") == 0 || strcmpi(type, "video") == 0 || + strcmpi(type, "image") == 0 || strcmpi(type, "executable") == 0 || + strcmpi(type, "file") == 0 || strcmpi(type, "folder") == 0) + { // setup the shares VECSOURCES *shares = NULL; if (!source || strcmpi(source, "") == 0) @@ -254,9 +345,10 @@ else shares = g_settings.GetSourcesFromType(source); - VECSOURCES localShares, networkShares; + VECSOURCES localShares; if (!shares) { + VECSOURCES networkShares; g_mediaManager.GetLocalDrives(localShares); if (!source || strcmpi(source, "local") != 0) g_mediaManager.GetNetworkLocations(networkShares); @@ -271,12 +363,12 @@ if (option) bWriteOnly = (strcmpi(option, "writeable") == 0); - if (CGUIDialogFileBrowser::ShowAndGetDirectory(*shares, ((CGUIButtonControl*) control)->GetLabel(), value, bWriteOnly)) + if (CGUIDialogFileBrowser::ShowAndGetDirectory(*shares, label, value, bWriteOnly)) ((CGUIButtonControl*) control)->SetLabel2(value); } - else if (strcmpi(type, "pictures") == 0) + else if (strcmpi(type, "image") == 0) { - if (CGUIDialogFileBrowser::ShowAndGetImage(*shares, ((CGUIButtonControl*) control)->GetLabel(), value)) + if (CGUIDialogFileBrowser::ShowAndGetImage(*shares, label, value)) ((CGUIButtonControl*) control)->SetLabel2(value); } else @@ -284,21 +376,22 @@ // set the proper mask CStdString strMask; if (setting->Attribute("mask")) + { strMask = setting->Attribute("mask"); + // convert mask qualifiers + strMask.Replace("$AUDIO", g_stSettings.m_musicExtensions); + strMask.Replace("$VIDEO", g_stSettings.m_videoExtensions); + strMask.Replace("$IMAGE", g_stSettings.m_pictureExtensions); + strMask.Replace("$EXECUTABLE", ".xbe|.py"); + } else { if (strcmpi(type, "video") == 0) strMask = g_stSettings.m_videoExtensions; - else if (strcmpi(type, "music") == 0) + else if (strcmpi(type, "audio") == 0) strMask = g_stSettings.m_musicExtensions; - else if (strcmpi(type, "programs") == 0) -#if defined(_XBOX) + else if (strcmpi(type, "executable") == 0) strMask = ".xbe|.py"; -#elif defined(_WIN32_WINNT) - strMask = ".exe|.bat|.cmd|.py"; -#else - strMask = ""; -#endif } // get any options @@ -306,27 +399,61 @@ bool bUseFileDirectories = false; if (option) { - bUseThumbs = (strcmpi(option, "usethumbs") == 0 || strcmpi(option, "usethumbs|treatasfolder") == 0); - bUseFileDirectories = (strcmpi(option, "treatasfolder") == 0 || strcmpi(option, "usethumbs|treatasfolder") == 0); + vector options; + StringUtils::SplitString(option, "|", options); + bUseThumbs = find(options.begin(), options.end(), "usethumbs") != options.end(); + bUseFileDirectories = find(options.begin(), options.end(), "treatasfolder") != options.end(); } - if (CGUIDialogFileBrowser::ShowAndGetFile(*shares, strMask, ((CGUIButtonControl*) control)->GetLabel(), value)) + if (CGUIDialogFileBrowser::ShowAndGetFile(*shares, strMask, label, value)) ((CGUIButtonControl*) control)->SetLabel2(value); } } else if (strcmpi(type, "action") == 0) { - if (setting->Attribute("default")) + CStdString action = setting->Attribute("action"); + if (!action.IsEmpty()) { - CStdString action = setting->Attribute("default"); CStdString url = m_url.Get(); - // replace $CWD with the url of plugin + CUtil::RemoveSlashAtEnd(url); + // replace $CWD with the url of plugin/script action.Replace("$CWD", url); + action.Replace("$ID", url); + action.Replace("/", "\\"); if (option) bCloseDialog = (strcmpi(option, "close") == 0); g_applicationMessenger.ExecBuiltIn(action); } } + else if (strcmp(type, "date") == 0) + { + CDateTime date; + if (!value.IsEmpty()) + date.SetFromDBDate(value); + SYSTEMTIME timedate; + date.GetAsSystemTime(timedate); + if(CGUIDialogNumeric::ShowAndGetDate(timedate, label)) + { + date = timedate; + value = date.GetAsDBDate(); + ((CGUIButtonControl*) control)->SetLabel2(value); + } + } + else if (strcmp(type, "time") == 0) + { + SYSTEMTIME timedate; + if (!value.IsEmpty()) + { + // assumes HH:MM + timedate.wHour = atoi(value.Left(2)); + timedate.wMinute = atoi(value.Right(2)); + } + if (CGUIDialogNumeric::ShowAndGetTime(timedate, label)) + { + value.Format("%02d:%02d", timedate.wHour, timedate.wMinute); + ((CGUIButtonControl*) control)->SetLabel2(value); + } + } m_buttonValues[id] = value; break; } @@ -338,24 +465,19 @@ return bCloseDialog; } -// Go over all the settings and set their values according to the values of the GUI components -bool CGUIDialogPluginSettings::SaveSettings(void) +void CGUIDialogPluginSettings::UpdateFromControls() { - // Retrieve all the values from the GUI components and put them in the model - int controlId = CONTROL_START_CONTROL; - TiXmlElement *setting = m_settings.GetPluginRoot()->FirstChildElement("setting"); + int controlID = CONTROL_START_SETTING; + const TiXmlElement *setting = GetFirstSetting(); + while (setting) { - CStdString id; - if (setting->Attribute("id")) - id = setting->Attribute("id"); + CStdString id = setting->Attribute("id"); const char *type = setting->Attribute("type"); + const CGUIControl* control = GetControl(controlID++); - // skip type "lsep", it is not a required control - if (strcmpi(type, "lsep") != 0) + if (control) { - const CGUIControl* control = GetControl(controlId); - CStdString value; switch (control->GetControlType()) { @@ -371,21 +493,46 @@ else value.Format("%i", ((CGUISpinControlEx*) control)->GetValue()); break; + case CGUIControl::GUICONTROL_SETTINGS_SLIDER: + value.Format("%f", ((CGUISettingsSliderControl *)control)->GetFloatValue()); + break; default: break; } - m_settings.Set(id, value); + m_settings[id] = value; } + setting = setting->NextSiblingElement("setting"); - controlId++; } - return true; } +void CGUIDialogPluginSettings::SaveSettings(void) +{ + UpdateFromControls(); + + for (map::iterator i = m_settings.begin(); i != m_settings.end(); ++i) + m_addon.Set(i->first, i->second); + + if (m_saveToDisk) + m_addon.Save(); +} + +void CGUIDialogPluginSettings::FreeSections() +{ + CGUIControlGroupList *group = (CGUIControlGroupList *)GetControl(CONTROL_SETTINGS_AREA); + if (group) + { + group->FreeResources(); + group->ClearAll(); + } + m_settings.clear(); + m_buttonValues.clear(); +} + void CGUIDialogPluginSettings::FreeControls() { // clear the category group - CGUIControlGroupList *control = (CGUIControlGroupList *)GetControl(CONTROL_AREA); + CGUIControlGroupList *control = (CGUIControlGroupList *)GetControl(CONTROL_SETTINGS_AREA); if (control) { control->FreeResources(); @@ -393,45 +540,88 @@ } } +void CGUIDialogPluginSettings::CreateSections() +{ + CGUIControlGroupList *group = (CGUIControlGroupList *)GetControl(CONTROL_SECTION_AREA); + CGUIButtonControl *originalButton = (CGUIButtonControl *)GetControl(CONTROL_DEFAULT_SECTION_BUTTON); + + if (originalButton) + originalButton->SetVisible(false); + + // clear the category group + FreeSections(); + + // grab our categories + const TiXmlElement *category = m_addon.GetPluginRoot()->FirstChildElement("category"); + if (!category) // add a default one... + category = m_addon.GetPluginRoot(); + + int buttonID = CONTROL_START_SECTION; + while (category) + { // add a category + CGUIButtonControl *button = originalButton ? originalButton->Clone() : NULL; + + CStdString label = GetString(category->Attribute("label")); + if (label.IsEmpty()) + label = g_localizeStrings.Get(128); + + // 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 char *id = setting->Attribute("id"); + if (id) + m_settings[id] = m_addon.Get(id); + setting = setting->NextSiblingElement("setting"); + } + category = category->NextSiblingElement("category"); + } + m_totalSections = buttonID - CONTROL_START_SECTION; +} + void CGUIDialogPluginSettings::CreateControls() { + FreeControls(); + CGUISpinControlEx *pOriginalSpin = (CGUISpinControlEx*)GetControl(CONTROL_DEFAULT_SPIN); CGUIRadioButtonControl *pOriginalRadioButton = (CGUIRadioButtonControl *)GetControl(CONTROL_DEFAULT_RADIOBUTTON); CGUIButtonControl *pOriginalButton = (CGUIButtonControl *)GetControl(CONTROL_DEFAULT_BUTTON); CGUIImage *pOriginalImage = (CGUIImage *)GetControl(CONTROL_DEFAULT_SEPARATOR); CGUILabelControl *pOriginalLabel = (CGUILabelControl *)GetControl(CONTROL_DEFAULT_LABEL_SEPARATOR); + CGUISettingsSliderControl *pOriginalSlider = (CGUISettingsSliderControl *)GetControl(CONTROL_DEFAULT_SLIDER); - if (!pOriginalSpin || !pOriginalRadioButton || !pOriginalButton || !pOriginalImage) + if (!pOriginalSpin || !pOriginalRadioButton || !pOriginalButton || !pOriginalImage + || !pOriginalLabel || !pOriginalSlider) return; pOriginalSpin->SetVisible(false); pOriginalRadioButton->SetVisible(false); pOriginalButton->SetVisible(false); pOriginalImage->SetVisible(false); - if (pOriginalLabel) - pOriginalLabel->SetVisible(false); + pOriginalLabel->SetVisible(false); + pOriginalSlider->SetVisible(false); // clear the category group - CGUIControlGroupList *group = (CGUIControlGroupList *)GetControl(CONTROL_AREA); + CGUIControlGroupList *group = (CGUIControlGroupList *)GetControl(CONTROL_SETTINGS_AREA); if (!group) return; // set our dialog heading SET_CONTROL_LABEL(CONTROL_HEADING_LABEL, m_strHeading); - // Create our base path, used for type "fileenum" settings - CStdString basepath; - if (m_url.GetProtocol().Equals("plugin")) - { // plugins need to create path - basepath = CUtil::AddFileToFolder("special://home/plugins/", m_url.GetHostName()); - basepath = CUtil::AddFileToFolder(basepath, m_url.GetFileName()); - } - else - basepath = m_url.Get(); + CGUIControl* pControl = NULL; + int controlId = CONTROL_START_SETTING; + const TiXmlElement *setting = GetFirstSetting(); - CGUIControl* pControl = NULL; - int controlId = CONTROL_START_CONTROL; - TiXmlElement *setting = m_settings.GetPluginRoot()->FirstChildElement("setting"); while (setting) { const char *type = setting->Attribute("type"); @@ -445,11 +635,8 @@ CStdString entries; if (setting->Attribute("entries")) entries = setting->Attribute("entries"); - CStdString label; - if (setting->Attribute("label") && atoi(setting->Attribute("label")) > 0) - label.Format("$LOCALIZE[%s]", setting->Attribute("label")); - else - label = setting->Attribute("label"); + const char *subsetting = setting->Attribute("subsetting"); + CStdString label = GetString(setting->Attribute("label"), subsetting && 0 == strcmpi(subsetting, "true")); bool bSort=false; const char *sort = setting->Attribute("sort"); @@ -459,10 +646,12 @@ if (type) { if (strcmpi(type, "text") == 0 || strcmpi(type, "ipaddress") == 0 || - strcmpi(type, "integer") == 0 || strcmpi(type, "video") == 0 || - strcmpi(type, "music") == 0 || strcmpi(type, "pictures") == 0 || - strcmpi(type, "folder") == 0 || strcmpi(type, "programs") == 0 || - strcmpi(type, "files") == 0 || strcmpi(type, "action") == 0) + strcmpi(type, "number") == 0 ||strcmpi(type, "video") == 0 || + strcmpi(type, "audio") == 0 || strcmpi(type, "image") == 0 || + strcmpi(type, "folder") == 0 || strcmpi(type, "executable") == 0 || + strcmpi(type, "file") == 0 || strcmpi(type, "action") == 0 || + strcmpi(type, "date") == 0 || strcmpi(type, "time") == 0 || + strcmpi(type, "select") == 0) { pControl = new CGUIButtonControl(*pOriginalButton); if (!pControl) return; @@ -470,8 +659,10 @@ ((CGUIButtonControl *)pControl)->SetLabel(label); if (id) { - m_buttonValues[id] = m_settings.Get(id); - CStdString value=m_settings.Get(id); + CStdString tmpS = m_settings[id]; + + CStdString value = m_settings[id]; + m_buttonValues[id] = value; // get any option to test for hidden const char *option = setting->Attribute("option"); if (option && (strstr(option, "urlencoded"))) @@ -485,13 +676,15 @@ else ((CGUIButtonControl *)pControl)->SetLabel2(value); } + else + ((CGUIButtonControl *)pControl)->SetLabel2(GetString(setting->Attribute("default"))); } else if (strcmpi(type, "bool") == 0) { pControl = new CGUIRadioButtonControl(*pOriginalRadioButton); if (!pControl) return; ((CGUIRadioButtonControl *)pControl)->SetLabel(label); - ((CGUIRadioButtonControl *)pControl)->SetSelected(m_settings.Get(id) == "true"); + ((CGUIRadioButtonControl *)pControl)->SetSelected(m_settings[id] == "true"); } else if (strcmpi(type, "enum") == 0 || strcmpi(type, "labelenum") == 0) { @@ -504,6 +697,14 @@ if (!lvalues.IsEmpty()) CUtil::Tokenize(lvalues, valuesVec, "|"); + else if (values.Equals("$HOURS")) + { + for (unsigned int i = 0; i < 24; i++) + { + CDateTime time(0, 0, 0, i, 0, 0); + valuesVec.push_back(g_infoManager.LocalizeTime(time, TIME_FORMAT_HH_MM_XX)); + } + } else CUtil::Tokenize(values, valuesVec, "|"); if (!entries.IsEmpty()) @@ -529,10 +730,10 @@ } if (strcmpi(type, "labelenum") == 0) { // need to run through all our settings and find the one that matches - ((CGUISpinControlEx*) pControl)->SetValueFromLabel(m_settings.Get(id)); + ((CGUISpinControlEx*) pControl)->SetValueFromLabel(m_settings[id]); } else - ((CGUISpinControlEx*) pControl)->SetValue(atoi(m_settings.Get(id))); + ((CGUISpinControlEx*) pControl)->SetValue(atoi(m_settings[id])); } else if (strcmpi(type, "fileenum") == 0) @@ -540,39 +741,51 @@ pControl = new CGUISpinControlEx(*pOriginalSpin); if (!pControl) return; ((CGUISpinControlEx *)pControl)->SetText(label); + ((CGUISpinControlEx *)pControl)->SetFloatValue(1.0f); - //find Folders... - CFileItemList items; - CStdString enumpath; - CUtil::AddFileToFolder(basepath, values, enumpath); - CStdString mask; - if (setting->Attribute("mask")) - mask = setting->Attribute("mask"); - if (!mask.IsEmpty()) - CDirectory::GetDirectory(enumpath, items, mask); - else - CDirectory::GetDirectory(enumpath, items); + vector items = GetFileEnumValues(values, setting->Attribute("mask"), setting->Attribute("option")); + for (unsigned int i = 0; i < items.size(); ++i) + { + ((CGUISpinControlEx *)pControl)->AddLabel(items[i], i); + if (items[i].Equals(m_settings[id])) + ((CGUISpinControlEx *)pControl)->SetValue(i); + } + } + else if (strcmpi(type, "slider") == 0) + { + pControl = new CGUISettingsSliderControl(*pOriginalSlider); + if (!pControl) return; + ((CGUISettingsSliderControl *)pControl)->SetText(label); - int iItem = 0; - for (int i = 0; i < items.Size(); ++i) + float fMin = 0.0f; + float fMax = 100.0f; + float fInc = 1.0f; + vector range; + StringUtils::SplitString(setting->Attribute("range"), ",", range); + if (range.size() > 1) { - CFileItemPtr pItem = items[i]; - if ((mask.Equals("/") && pItem->m_bIsFolder) || !pItem->m_bIsFolder) + fMin = (float)atof(range[0]); + if (range.size() > 2) { - ((CGUISpinControlEx *)pControl)->AddLabel(pItem->GetLabel(), iItem); - if (pItem->GetLabel().Equals(m_settings.Get(id))) - ((CGUISpinControlEx *)pControl)->SetValue(iItem); - iItem++; + fMax = (float)atof(range[2]); + fInc = (float)atof(range[1]); } + else + fMax = (float)atof(range[1]); } + + ((CGUISettingsSliderControl *)pControl)->SetType(SPIN_CONTROL_TYPE_FLOAT); + ((CGUISettingsSliderControl *)pControl)->SetFloatRange(fMin, fMax); + ((CGUISettingsSliderControl *)pControl)->SetFloatInterval(fInc); + ((CGUISettingsSliderControl *)pControl)->SetFloatValue((float)atof(m_settings[id])); } - else if (strcmpi(type, "lsep") == 0 && pOriginalLabel) + else if (strcmpi(type, "lsep") == 0) { pControl = new CGUILabelControl(*pOriginalLabel); if (pControl) ((CGUILabelControl *)pControl)->SetLabel(label); } - else if ((strcmpi(type, "sep") == 0 || strcmpi(type, "lsep") == 0) && pOriginalImage) + else if (strcmpi(type, "sep") == 0) pControl = new CGUIImage(*pOriginalImage); } @@ -592,11 +805,49 @@ EnableControls(); } +vector CGUIDialogPluginSettings::GetFileEnumValues(const CStdString &path, const CStdString &mask, const CStdString &options) const +{ + // Create our base path, used for type "fileenum" settings + // replace $PROFILE with the profile path of the plugin/script + CStdString fullPath = path; + CStdString url = m_url.Get(); + url.Replace("plugin://", "special://home/plugins/"); + + if (fullPath.Find("$PROFILE") >= 0) + { + fullPath.Replace("$PROFILE", m_profile); + } + else + fullPath = CUtil::AddFileToFolder(url, path); + + bool hideExtensions = (options.CompareNoCase("hideext") == 0); + // fetch directory + CFileItemList items; + if (!mask.IsEmpty()) + CDirectory::GetDirectory(fullPath, items, mask); + else + CDirectory::GetDirectory(fullPath, items); + + vector values; + for (int i = 0; i < items.Size(); ++i) + { + CFileItemPtr pItem = items[i]; + if ((mask.Equals("/") && 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 CGUIDialogPluginSettings::EnableControls() { - int controlId = CONTROL_START_CONTROL; - TiXmlElement *setting = m_settings.GetPluginRoot()->FirstChildElement("setting"); + int controlId = CONTROL_START_SETTING; + const TiXmlElement *setting = GetFirstSetting(); + while (setting) { const CGUIControl* control = GetControl(controlId); @@ -651,7 +902,10 @@ value = ((CGUIRadioButtonControl*) control2)->IsSelected() ? "true" : "false"; break; case CGUIControl::GUICONTROL_SPINEX: - value.Format("%i", ((CGUISpinControlEx*) control2)->GetValue()); + if (((CGUISpinControlEx*) control2)->GetFloatValue() > 0.0f) + value = ((CGUISpinControlEx*) control2)->GetLabel(); + else + value.Format("%i", ((CGUISpinControlEx*) control2)->GetValue()); break; default: break; @@ -709,55 +963,124 @@ return false; } +CStdString CGUIDialogPluginSettings::GetString(const char *value, bool subSetting) const +{ + if (!value) + return ""; + // Replace all $ADDON[id number] with the real string + CStdString label = ReplaceAddonStrings(value); + + int id = atoi(label); + CStdString prefix(subSetting ? "- " : ""); + if (id > 0) + return prefix + g_localizeStringsTemp.Get(id); + return prefix + label; +} + +CStdString CGUIDialogPluginSettings::ReplaceAddonStrings(const CStdString &label) +{ + CStdString work(label); + //FIXME why not use RE here? + // Replace all $ADDON[id number] with the real string + int pos1 = work.Find("$ADDON["); + while (pos1 >= 0) + { + int pos2 = StringUtils::FindEndBracket(work, '[', ']', pos1 + 7); + if (pos2 > pos1) + { + CStdString left = work.Left(pos1); + CStdString right = work.Mid(pos2 + 1); + int length = work.Find(" ", pos1 + 7) - (pos1 + 7); + CStdString id = work.substr(pos1+7, length); + int stringid = atoi(work.substr(pos1+7+id.length()+1, 5).c_str()); + CStdString replace = g_localizeStringsTemp.Get(stringid); + work = left + replace + right; + } + else + { + CLog::Log(LOGERROR, "Error parsing label - missing ']'"); + return ""; + } + pos1 = work.Find("$ADDON[", pos1); + } + return work; +} + // Go over all the settings and set their default values void CGUIDialogPluginSettings::SetDefaults() { - int controlId = CONTROL_START_CONTROL; - TiXmlElement *setting = m_settings.GetPluginRoot()->FirstChildElement("setting"); - while (setting) + const TiXmlElement *category = m_addon.GetPluginRoot()->FirstChildElement("category"); + if (!category) // add a default one... + category = m_addon.GetPluginRoot(); + + while (category) { - const CGUIControl* control = GetControl(controlId); - if (control) + const TiXmlElement *setting = category->FirstChildElement("setting"); + while (setting) { - CStdString value; - switch (control->GetControlType()) + const char *id = setting->Attribute("id"); + const char *type = setting->Attribute("type"); + const char *value = setting->Attribute("default"); + if (id) { - case CGUIControl::GUICONTROL_BUTTON: - if (setting->Attribute("default") && setting->Attribute("id")) - ((CGUIButtonControl*) control)->SetLabel2(setting->Attribute("default")); - else - ((CGUIButtonControl*) control)->SetLabel2(""); - break; - case CGUIControl::GUICONTROL_RADIO: - if (setting->Attribute("default")) - ((CGUIRadioButtonControl*) control)->SetSelected(strcmpi(setting->Attribute("default"), "true") == 0); - else - ((CGUIRadioButtonControl*) control)->SetSelected(false); - break; - case CGUIControl::GUICONTROL_SPINEX: - { - if (setting->Attribute("default")) - { - if (strcmpi(setting->Attribute("type"), "fileenum") == 0 || strcmpi(setting->Attribute("type"), "labelenum") == 0) - { // need to run through all our settings and find the one that matches - ((CGUISpinControlEx*) control)->SetValueFromLabel(setting->Attribute("default")); - } - else - ((CGUISpinControlEx*) control)->SetValue(atoi(setting->Attribute("default"))); - } - else - ((CGUISpinControlEx*) control)->SetValue(0); - } - break; - default: - break; + if (value) + m_settings[id] = value; + else if (0 == strcmpi(type, "bool")) + m_settings[id] = "false"; + else if (0 == strcmpi(type, "slider") || 0 == strcmpi(type, "enum")) + m_settings[id] = "0"; + else if (0 != strcmpi(type, "action")) + m_settings[id] = ""; } + setting = setting->NextSiblingElement("setting"); } - setting = setting->NextSiblingElement("setting"); - controlId++; + category = category->NextSiblingElement("category"); } - EnableControls(); + CreateControls(); } +const TiXmlElement *CGUIDialogPluginSettings::GetFirstSetting() +{ + const TiXmlElement *category = m_addon.GetPluginRoot()->FirstChildElement("category"); + if (!category) + category = m_addon.GetPluginRoot(); + for (unsigned int i = 0; i < m_currentSection && category; i++) + category = category->NextSiblingElement("category"); + if (category) + return category->FirstChildElement("setting"); + return NULL; +} + +void CGUIDialogPluginSettings::Render() +{ + // 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::Render(); + if (alphaFaded && m_bRunning) // dialog may close during Render() + { + control->SetFocus(false); + if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON) + ((CGUIButtonControl *)control)->SetAlpha(0xFF); + else + ((CGUIButtonControl *)control)->SetSelected(false); + } +} + CURL CGUIDialogPluginSettings::m_url; Index: xbmc/GUIDialogPluginSettings.h =================================================================== --- xbmc/GUIDialogPluginSettings.h (revision 30503) +++ xbmc/GUIDialogPluginSettings.h (working copy) @@ -33,27 +33,63 @@ CGUIDialogPluginSettings(void); virtual ~CGUIDialogPluginSettings(void); virtual bool OnMessage(CGUIMessage& message); - static bool ShowAndGetInput(CURL& url); - static bool ShowAndGetInput(SScraperInfo& info); - static bool ShowAndGetInput(CStdString& path); + /*! \brief Show the addon settings dialog, allowing the user to configure an addon + \param addon the addon to configure + \param saveToDisk whether the changes should be saved to disk or just made local to the addon. Defaults to true + \return true if settings were changed and the dialog confirmed, false otherwise. + */ + static bool ShowAndGetInput(CURL& url, bool saveToDisk = true); + static bool ShowAndGetInput(SScraperInfo& info, bool saveToDisk = true); + static bool ShowAndGetInput(CStdString& path, bool saveToDisk = true); + virtual void Render(); + static CStdString ReplaceAddonStrings(const CStdString &label); protected: virtual void OnInitWindow(); private: + /*! \brief return a (localized) addon string. + \param value either a character string (which is used directly) or a number to lookup in the addons strings.xml + \param subsetting whether the character string should be prefixed by "- ", defaults to false + \return the localized addon string + */ + CStdString GetString(const char *value, bool subSetting = false) const; + + /*! \brief return a the values for a fileenum setting + \param path the path to use for files + \param mask the mask to use + \param options any options, such as "hideext" to hide extensions + \return the filenames in the path that match the mask + */ + std::vector GetFileEnumValues(const CStdString &path, const CStdString &mask, const CStdString &options) const; + + void CreateSections(); + void FreeSections(); void CreateControls(); void FreeControls(); + void UpdateFromControls(); void EnableControls(); void SetDefaults(); bool GetCondition(const CStdString &condition, const int controlId); - - bool SaveSettings(void); + + void SaveSettings(void); bool ShowVirtualKeyboard(int iControl); - static CURL m_url; bool TranslateSingleString(const CStdString &strCondition, std::vector &enableVec); - CBasicSettings m_settings; + + const TiXmlElement *GetFirstSetting(); + + CBasicSettings m_addon; CStdString m_strHeading; + CStdString m_profile; std::map m_buttonValues; + bool m_changed; + bool m_saveToDisk; // whether the addon settings should be saved to disk or just stored locally in the addon + + unsigned int m_currentSection; + unsigned int m_totalSections; + + std::map m_settings; // local storage of values + static CURL m_url; }; #endif Index: xbmc/GUIDialogTextViewer.cpp =================================================================== --- xbmc/GUIDialogTextViewer.cpp (revision 0) +++ xbmc/GUIDialogTextViewer.cpp (revision 0) @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2005-2008 Team XBMC + * http://www.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, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GUIDialogTextViewer.h" + +#define CONTROL_HEADING 1 +#define CONTROL_TEXTAREA 5 + +CGUIDialogTextViewer::CGUIDialogTextViewer(void) + : CGUIDialog(WINDOW_DIALOG_TEXT_VIEWER, "DialogTextViewer.xml") +{} + +CGUIDialogTextViewer::~CGUIDialogTextViewer(void) +{} + +bool CGUIDialogTextViewer::OnAction(const CAction &action) +{ + return CGUIDialog::OnAction(action); +} + +bool CGUIDialogTextViewer::OnMessage(CGUIMessage& message) +{ + switch ( message.GetMessage() ) + { + case GUI_MSG_WINDOW_INIT: + { + CGUIDialog::OnMessage(message); + SetHeading(); + SetText(); + return true; + } + break; + case GUI_MSG_NOTIFY_ALL: + { + if (message.GetParam1() == GUI_MSG_UPDATE) + { + SetText(); + SetHeading(); + return true; + } + } + break; + default: + break; + } + return CGUIDialog::OnMessage(message); +} + +void CGUIDialogTextViewer::SetText() +{ + CGUIMessage msg(GUI_MSG_LABEL_SET, GetID(), CONTROL_TEXTAREA); + msg.SetLabel(m_strText); + OnMessage(msg); +} + +void CGUIDialogTextViewer::SetHeading() +{ + CGUIMessage msg(GUI_MSG_LABEL_SET, GetID(), CONTROL_HEADING); + msg.SetLabel(m_strHeading); + OnMessage(msg); +} + Index: xbmc/GUIDialogTextViewer.h =================================================================== --- xbmc/GUIDialogTextViewer.h (revision 0) +++ xbmc/GUIDialogTextViewer.h (revision 0) @@ -0,0 +1,43 @@ +#pragma once + +/* + * Copyright (C) 2005-2008 Team XBMC + * http://www.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, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "GUIDialog.h" + +class CGUIDialogTextViewer : + public CGUIDialog +{ +public: + CGUIDialogTextViewer(void); + virtual ~CGUIDialogTextViewer(void); + virtual bool OnMessage(CGUIMessage& message); + virtual bool OnAction(const CAction &action); + void SetText(const CStdString& strText) { m_strText = strText; } + void SetHeading(const CStdString& strHeading) { m_strHeading = strHeading; } +protected: + CStdString m_strText; + CStdString m_strHeading; + + void SetText(); + void SetHeading(); +}; + Index: xbmc/lib/libPython/xbmcmodule/keyboard.cpp =================================================================== --- xbmc/lib/libPython/xbmcmodule/keyboard.cpp (revision 30503) +++ xbmc/lib/libPython/xbmcmodule/keyboard.cpp (working copy) @@ -71,10 +71,12 @@ // doModal() Method PyDoc_STRVAR(doModal__doc__, - "doModal() -- Show keyboard and wait for user action.\n" + "doModal([autoclose]) -- Show keyboard and wait for user action.\n" "\n" + "autoclose : [opt] integer - milliseconds to autoclose dialog. (default=do not autoclose)\n" + "\n" "example:\n" - " - kb.doModal()"); + " - kb.doModal(30000)"); PyObject* Keyboard_DoModal(Keyboard *self, PyObject *args) { @@ -84,13 +86,18 @@ PyErr_SetString(PyExc_SystemError, "Unable to load virtual keyboard"); return NULL; } + int autoClose = 0; + if (!PyArg_ParseTuple(args, (char*)"|i", &autoClose)) return NULL; + pKeyboard->Initialize(); pKeyboard->CenterWindow(); pKeyboard->SetHeading(self->strHeading); CStdString strDefault(self->strDefault); pKeyboard->SetText(strDefault); pKeyboard->SetHiddenInput(self->bHidden); + if (autoClose > 0) + pKeyboard->SetAutoClose(autoClose); // do modal of dialog ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_KEYBOARD, g_windowManager.GetActiveWindow()}; Index: xbmc/lib/libPython/xbmcmodule/player.cpp =================================================================== --- xbmc/lib/libPython/xbmcmodule/player.cpp (revision 30503) +++ xbmc/lib/libPython/xbmcmodule/player.cpp (working copy) @@ -294,7 +294,7 @@ // Player_OnPlayBackResumed PyDoc_STRVAR(onPlayBackResumed__doc__, - "onPlayBackPaused() -- onPlayBackResumed method.\n" + "onPlayBackResumed() -- onPlayBackResumed method.\n" "\n" "Will be called when user resumes a paused file"); Index: xbmc/lib/libPython/xbmcmodule/winxml.cpp =================================================================== --- xbmc/lib/libPython/xbmcmodule/winxml.cpp (revision 30503) +++ xbmc/lib/libPython/xbmcmodule/winxml.cpp (working copy) @@ -56,61 +56,45 @@ PyObject* pyOXMLname = NULL; PyObject* pyOname = NULL; PyObject* pyDName = NULL; + PyObject* pyRes = NULL; char bForceDefaultSkin = false; string strXMLname, strFallbackPath; string strDefault = "Default"; + string resolution = "720p"; - if (!PyArg_ParseTuple(args, (char*)"OO|Ob", &pyOXMLname, &pyOname, &pyDName, &bForceDefaultSkin )) return NULL; + if (!PyArg_ParseTuple(args, (char*)"OO|OO", &pyOXMLname, &pyOname, &pyDName, &pyRes)) return NULL; PyXBMCGetUnicodeString(strXMLname, pyOXMLname); PyXBMCGetUnicodeString(strFallbackPath, pyOname); if (pyDName) PyXBMCGetUnicodeString(strDefault, pyDName); + if (pyRes) PyXBMCGetUnicodeString(resolution, pyRes); RESOLUTION res; - CStdString strSkinPath; - if (!bForceDefaultSkin) + CStdString strSkinPath = g_SkinInfo.GetSkinPath(strXMLname, &res); + + // Check to see if the XML file exists in current skin. If not use fallback path to find a skin for the script + if (!XFILE::CFile::Exists(strSkinPath)) { - // Check to see if the XML file exists in current skin. If not use fallback path to find a skin for the script - strSkinPath = g_SkinInfo.GetSkinPath(strXMLname, &res); - + // Check for the matching folder for the skin in the fallback skins folder + CStdString fallbackPath = CUtil::AddFileToFolder(strFallbackPath, "resources"); + fallbackPath = CUtil::AddFileToFolder(fallbackPath, "skins"); + CStdString basePath = CUtil::AddFileToFolder(fallbackPath, CUtil::GetFileName(g_SkinInfo.GetBaseDir())); + strSkinPath = g_SkinInfo.GetSkinPath(strXMLname, &res, basePath); if (!XFILE::CFile::Exists(strSkinPath)) { - // Check for the matching folder for the skin in the fallback skins folder - CStdString basePath; - CUtil::AddFileToFolder(strFallbackPath, "resources", basePath); - CUtil::AddFileToFolder(basePath, "skins", basePath); - CUtil::AddFileToFolder(basePath, CUtil::GetFileName(g_SkinInfo.GetBaseDir()), basePath); - strSkinPath = g_SkinInfo.GetSkinPath(strXMLname, &res, basePath); + // Finally fallback to the DefaultSkin as it didn't exist in either the XBMC Skin folder or the fallback skin folder + CStdString basePath = CUtil::AddFileToFolder(fallbackPath, strDefault); + res = CSkinInfo::TranslateResolution(resolution, HDTV_720p); + CSkinInfo skinInfo; + strSkinPath = skinInfo.GetSkinPath(strXMLname, &res, basePath); if (!XFILE::CFile::Exists(strSkinPath)) { - // Finally fallback to the DefaultSkin as it didn't exist in either the XBMC Skin folder or the fallback skin folder - bForceDefaultSkin = true; + PyErr_SetString(PyExc_TypeError, "XML File for Window is missing"); + return NULL; } } } - - if (bForceDefaultSkin) - { - CSkinInfo skinInfo; - CStdString basePath; - CUtil::AddFileToFolder(strFallbackPath, "resources", basePath); - CUtil::AddFileToFolder(basePath, "skins", basePath); - CUtil::AddFileToFolder(basePath, strDefault, basePath); - - skinInfo.Load(basePath); - // if no skin.xml file exists default to PAL_4x3 and PAL_16x9 - if (skinInfo.GetDefaultResolution() == INVALID) - skinInfo.SetDefaults(); - strSkinPath = skinInfo.GetSkinPath(strXMLname, &res, basePath); - - if (!XFILE::CFile::Exists(strSkinPath)) - { - PyErr_SetString(PyExc_TypeError, "XML File for Window is missing"); - return NULL; - } - } - self->sFallBackPath = strFallbackPath; self->sXMLFileName = strSkinPath; self->bUsingXML = true; @@ -381,17 +365,17 @@ PyDoc_STRVAR(windowXML__doc__, "WindowXML class.\n" "\n" - "WindowXML(self, xmlFilename, scriptPath[, defaultSkin, forceFallback) -- Create a new WindowXML script.\n" + "WindowXML(self, xmlFilename, scriptPath[, defaultSkin, defaultRes]) -- Create a new WindowXML script.\n" "\n" "xmlFilename : string - the name of the xml file to look for.\n" "scriptPath : string - path to script. used to fallback to if the xml doesn't exist in the current skin. (eg os.getcwd())\n" "defaultSkin : [opt] string - name of the folder in the skins path to look in for the xml. (default='Default')\n" - "forceFallback : [opt] boolean - if true then it will look only in the defaultSkin folder. (default=False)\n" + "defaultRes : [opt] string - default skins resolution. (default='720p')\n" "\n" - "*Note, skin folder structure is eg(resources/skins/Default/PAL)\n" + "*Note, skin folder structure is eg(resources/skins/Default/720p)\n" "\n" "example:\n" - " - ui = GUI('script-AMT-main.xml', os.getcwd(), 'LCARS', True)\n" + " - ui = GUI('script-Lyrics-main.xml', os.getcwd(), 'LCARS', 'PAL')\n" " ui.doModal()\n" " del ui\n"); Index: xbmc/lib/libPython/xbmcmodule/winxmldialog.cpp =================================================================== --- xbmc/lib/libPython/xbmcmodule/winxmldialog.cpp (revision 30503) +++ xbmc/lib/libPython/xbmcmodule/winxmldialog.cpp (working copy) @@ -56,61 +56,44 @@ PyObject* pyOXMLname = NULL; PyObject* pyOname = NULL; PyObject* pyDName = NULL; - char bForceDefaultSkin = false; + PyObject* pyRes = NULL; string strXMLname, strFallbackPath; string strDefault = "Default"; + string resolution = "720p"; - if (!PyArg_ParseTuple(args, (char*)"OO|Ob", &pyOXMLname, &pyOname, &pyDName, &bForceDefaultSkin )) return NULL; + if (!PyArg_ParseTuple(args, (char*)"OO|OO", &pyOXMLname, &pyOname, &pyDName, &pyRes)) return NULL; PyXBMCGetUnicodeString(strXMLname, pyOXMLname); PyXBMCGetUnicodeString(strFallbackPath, pyOname); if (pyDName) PyXBMCGetUnicodeString(strDefault, pyDName); + if (pyRes) PyXBMCGetUnicodeString(resolution, pyRes); RESOLUTION res; - CStdString strSkinPath; - if (!bForceDefaultSkin) + CStdString strSkinPath = g_SkinInfo.GetSkinPath(strXMLname, &res); + + // Check to see if the XML file exists in current skin. If not use fallback path to find a skin for the script + if (!XFILE::CFile::Exists(strSkinPath)) { - // Check to see if the XML file exists in current skin. If not use fallback path to find a skin for the script - strSkinPath = g_SkinInfo.GetSkinPath(strXMLname, &res); - + // Check for the matching folder for the skin in the fallback skins folder + CStdString fallbackPath = CUtil::AddFileToFolder(strFallbackPath, "resources"); + fallbackPath = CUtil::AddFileToFolder(fallbackPath, "skins"); + CStdString basePath = CUtil::AddFileToFolder(fallbackPath, CUtil::GetFileName(g_SkinInfo.GetBaseDir())); + strSkinPath = g_SkinInfo.GetSkinPath(strXMLname, &res, basePath); if (!XFILE::CFile::Exists(strSkinPath)) { - // Check for the matching folder for the skin in the fallback skins folder - CStdString basePath; - CUtil::AddFileToFolder(strFallbackPath, "resources", basePath); - CUtil::AddFileToFolder(basePath, "skins", basePath); - CUtil::AddFileToFolder(basePath, CUtil::GetFileName(g_SkinInfo.GetBaseDir()), basePath); - strSkinPath = g_SkinInfo.GetSkinPath(strXMLname, &res, basePath); + // Finally fallback to the DefaultSkin as it didn't exist in either the XBMC Skin folder or the fallback skin folder + CStdString basePath = CUtil::AddFileToFolder(fallbackPath, strDefault); + res = CSkinInfo::TranslateResolution(resolution, HDTV_720p); + CSkinInfo skinInfo; + strSkinPath = skinInfo.GetSkinPath(strXMLname, &res, basePath); if (!XFILE::CFile::Exists(strSkinPath)) { - // Finally fallback to the DefaultSkin as it didn't exist in either the XBMC Skin folder or the fallback skin folder - bForceDefaultSkin = true; + PyErr_SetString(PyExc_TypeError, "XML File for Window is missing"); + return NULL; } } } - - if (bForceDefaultSkin) - { - CSkinInfo skinInfo; - CStdString basePath; - CUtil::AddFileToFolder(strFallbackPath, "resources", basePath); - CUtil::AddFileToFolder(basePath, "skins", basePath); - CUtil::AddFileToFolder(basePath, strDefault, basePath); - - skinInfo.Load(basePath); - // if no skin.xml file exists default to PAL_4x3 and PAL_16x9 - if (skinInfo.GetDefaultResolution() == INVALID) - skinInfo.SetDefaults(); - strSkinPath = skinInfo.GetSkinPath(strXMLname, &res, basePath); - - if (!XFILE::CFile::Exists(strSkinPath)) - { - PyErr_SetString(PyExc_TypeError, "XML File for Window is missing"); - return NULL; - } - } - self->sFallBackPath = strFallbackPath; self->sXMLFileName = strSkinPath; self->bUsingXML = true; @@ -129,17 +112,17 @@ PyDoc_STRVAR(windowXMLDialog__doc__, "WindowXMLDialog class.\n" "\n" - "WindowXMLDialog(self, xmlFilename, scriptPath[, defaultSkin, forceFallback) -- Create a new WindowXMLDialog script.\n" + "WindowXMLDialog(self, xmlFilename, scriptPath[, defaultSkin, defaultRes]) -- Create a new WindowXMLDialog script.\n" "\n" "xmlFilename : string - the name of the xml file to look for.\n" "scriptPath : string - path to script. used to fallback to if the xml doesn't exist in the current skin. (eg os.getcwd())\n" "defaultSkin : [opt] string - name of the folder in the skins path to look in for the xml. (default='Default')\n" - "forceFallback : [opt] boolean - if true then it will look only in the defaultSkin folder. (default=False)\n" + "defaultRes : [opt] string - default skins resolution. (default='720p')\n" "\n" - "*Note, skin folder structure is eg(resources/skins/Default/PAL)\n" + "*Note, skin folder structure is eg(resources/skins/Default/720p)\n" "\n" "example:\n" - " - ui = GUI('script-Lyrics-main.xml', os.getcwd(), 'LCARS', True)\n" + " - ui = GUI('script-Lyrics-main.xml', os.getcwd(), 'LCARS', 'PAL')\n" " ui.doModal()\n" " del ui\n"); Index: xbmc/lib/libPython/xbmcmodule/xbmcmodule.cpp =================================================================== --- xbmc/lib/libPython/xbmcmodule/xbmcmodule.cpp (revision 30503) +++ xbmc/lib/libPython/xbmcmodule/xbmcmodule.cpp (working copy) @@ -658,7 +658,7 @@ if (!PyXBMCGetUnicodeString(strText, pObjectText, 1)) return NULL; CStdString strFilename; - strFilename = CUtil::MakeLegalPath(strText); + strFilename = CUtil::MakeLegalPath(strText, LEGAL_FATX); return Py_BuildValue((char*)"s", strFilename.c_str()); } Index: xbmc/lib/libPython/XBPyThread.cpp =================================================================== --- xbmc/lib/libPython/XBPyThread.cpp (revision 30503) +++ xbmc/lib/libPython/XBPyThread.cpp (working copy) @@ -25,6 +25,8 @@ #include "Python/osdefs.h" #include "XBPythonDll.h" #include "FileSystem/SpecialProtocol.h" +#include "FileSystem/Directory.h" +#include "FileItem.h" #include "GUIWindowManager.h" #include "GUIDialogKaiToast.h" #include "Util.h" @@ -136,8 +138,6 @@ { CLog::Log(LOGDEBUG,"Python thread: start processing"); - char path[1024]; - char sourcedir[1024]; int m_Py_file_input = Py_file_input; // get the global lock @@ -149,29 +149,40 @@ // get path from script file name and add python path's // this is used for python so it will search modules from script path first - strcpy(sourcedir, _P(source)); + CStdString scriptDir; + CUtil::GetDirectory(_P(source), scriptDir); + CUtil::RemoveSlashAtEnd(scriptDir); + CStdString path = scriptDir; - char *p = strrchr(sourcedir, PATH_SEPARATOR_CHAR); - *p = PY_PATH_SEP; - *++p = 0; + // add on any addon modules the user has installed + // fetch directory + CFileItemList items; + DIRECTORY::CDirectory::GetDirectory("Q:\\scripts\\.modules", items, "/"); + for (int i = 0; i < items.Size(); ++i) + { + CFileItemPtr pItem = items[i]; + if (pItem->m_bIsFolder) + { + CStdString fullpath = CUtil::AddFileToFolder(pItem->m_strPath, "lib"); + path += PY_PATH_SEP + fullpath; + } + } + // and add on whatever our default path is + path += PY_PATH_SEP; + path += dll_getenv("PYTHONPATH"); - strcpy(path, sourcedir); - strcat(path, dll_getenv("PYTHONPATH")); - // set current directory and python's path. if (argv != NULL) PySys_SetArgv(argc, argv); - CLog::Log(LOGDEBUG, "%s - Setting the Python path to %s", __FUNCTION__, path); + CLog::Log(LOGDEBUG, "%s - Setting the Python path to %s", __FUNCTION__, path.c_str()); - PySys_SetPath(path); - // Remove the PY_PATH_SEP at the end - sourcedir[strlen(sourcedir)-1] = 0; - - CLog::Log(LOGDEBUG, "%s - Entering source directory %s", __FUNCTION__, sourcedir); - - xbp_chdir(sourcedir); - + PySys_SetPath((char *)path.c_str()); + + CLog::Log(LOGDEBUG, "%s - Entering source directory %s", __FUNCTION__, scriptDir.c_str()); + + xbp_chdir(scriptDir.c_str()); + int retval = -1; if (type == 'F') @@ -321,6 +332,4 @@ threadState->use_tracing = 1; PyEval_ReleaseLock(); - - } Index: xbmc/PluginSettings.cpp =================================================================== --- xbmc/PluginSettings.cpp (revision 30503) +++ xbmc/PluginSettings.cpp (working copy) @@ -107,15 +107,24 @@ if (m_pluginXmlDoc.RootElement()) { - // Try to find the setting in the plugin and return its default value - const TiXmlElement* setting = m_pluginXmlDoc.RootElement()->FirstChildElement("setting"); - while (setting) + const TiXmlElement *category = m_pluginXmlDoc.RootElement()->FirstChildElement("category"); + // this makes grouping optional + if (!category) + category = m_pluginXmlDoc.RootElement(); + + while (category) { - const char *id = setting->Attribute("id"); - if (id && strcmpi(id, key) == 0 && setting->Attribute("default")) - return setting->Attribute("default"); + // Try to find the setting in the plugin and return its default value + const TiXmlElement* setting = category->FirstChildElement("setting"); + while (setting) + { + const char *id = setting->Attribute("id"); + if (id && strcmpi(id, key) == 0 && setting->Attribute("default")) + return setting->Attribute("default"); - setting = setting->NextSiblingElement("setting"); + setting = setting->NextSiblingElement("setting"); + } + category = category->NextSiblingElement("category"); } } Index: xbmc/Util.cpp =================================================================== --- xbmc/Util.cpp (revision 30503) +++ xbmc/Util.cpp (working copy) @@ -3269,8 +3269,22 @@ // check if the filename is a legal FATX one. if (LegalType == LEGAL_FATX) { + result.Replace(':', '_'); + result.Replace('*', '_'); + result.Replace('?', '_'); + result.Replace('\"', '_'); + result.Replace('<', '_'); + result.Replace('>', '_'); + result.Replace('|', '_'); + result.Replace(',', '_'); + result.Replace('=', '_'); + result.Replace('+', '_'); + result.Replace(';', '_'); + result.Replace('"', '_'); + result.Replace('\'', '_'); result.TrimRight("."); result.TrimRight(" "); + GetFatXQualifiedPath(result); } @@ -3419,7 +3433,8 @@ { "Control.Message", true, "Send a given message to a control within a given window" }, { "SendClick", true, "Send a click message from the given control to the given window" }, { "LoadProfile", true, "Load the specified profile (note; if locks are active it won't work)" }, - { "SetProperty", true, "Sets a window property for the current window (key,value)" }, + { "SetProperty", true, "Sets a window property for the current focused window/dialog (key,value)" }, + { "ClearProperty", true, "Clears a window property for the current focused window/dialog (key,value)" }, { "PlayWith", true, "Play the selected item with the specified core" }, { "WakeOnLan", true, "Sends the wake-up packet to the broadcast address for the specified MAC address" } }; @@ -4611,10 +4626,16 @@ } else if (execute.Equals("setproperty") && params.size() == 2) { - CGUIWindow *window = g_windowManager.GetWindow(g_windowManager.GetActiveWindow()); + CGUIWindow *window = g_windowManager.GetWindow(g_windowManager.GetFocusedWindow()); if (window) window->SetProperty(params[0],params[1]); } + else if (execute.Equals("clearproperty") && params.size() == 2) + { + CGUIWindow *window = g_windowManager.GetWindow(g_windowManager.GetFocusedWindow()); + if (window) + window->SetProperty(params[0],""); + } else if (execute.Equals("wakeonlan")) { g_network.WakeOnLan((char*)params[0].c_str()); Index: xbmc/utils/GUIInfoManager.cpp =================================================================== --- xbmc/utils/GUIInfoManager.cpp (revision 30503) +++ xbmc/utils/GUIInfoManager.cpp (working copy) @@ -969,6 +969,7 @@ else if (info.Equals("exists")) return MUSICPLAYER_EXISTS; else if (info.Equals("hasprevious")) return MUSICPLAYER_HASPREVIOUS; else if (info.Equals("hasnext")) return MUSICPLAYER_HASNEXT; + else if (info.Equals("filename")) return MUSICPLAYER_FILENAME; return 0; } @@ -1120,6 +1121,7 @@ case MUSICPLAYER_RATING: case MUSICPLAYER_COMMENT: case MUSICPLAYER_LYRICS: + case MUSICPLAYER_FILENAME: strLabel = GetMusicLabel(info); break; case VIDEOPLAYER_TITLE: @@ -2550,7 +2552,7 @@ return ((CGUITextBox *)control)->GetLabel(info.m_info); } } - else if (info.m_info >= MUSICPLAYER_TITLE && info.m_info <= MUSICPLAYER_DISC_NUMBER) + else if (info.m_info >= MUSICPLAYER_TITLE && info.m_info <= MUSICPLAYER_FILENAME) return GetMusicPlaylistInfo(info); else if (info.m_info == CONTAINER_PROPERTY) { @@ -2585,7 +2587,7 @@ } else { // no window specified - assume active - window = g_windowManager.GetWindow(g_windowManager.GetActiveWindow()); + window = GetWindowWithCondition(contextWindow, 0); } if (window) @@ -2996,6 +2998,12 @@ case MUSICPLAYER_TITLE: if (tag.GetTitle().size()) { return tag.GetTitle(); } break; + case MUSICPLAYER_FILENAME: + if (tag.GetURL().size()) { return tag.GetURL(); } + break; + case MUSICPLAYER_LYRICS: + if (tag.GetLyrics().size()) { return tag.GetLyrics(); } + break; case MUSICPLAYER_ALBUM: if (tag.GetAlbum().size()) { return tag.GetAlbum(); } break; Index: xbmc/utils/GUIInfoManager.h =================================================================== --- xbmc/utils/GUIInfoManager.h (revision 30503) +++ xbmc/utils/GUIInfoManager.h (working copy) @@ -212,6 +212,7 @@ #define MUSICPLAYER_EXISTS 224 #define MUSICPLAYER_PLAYLISTPLAYING 225 #define MUSICPLAYER_ALBUM_ARTIST 226 +#define MUSICPLAYER_FILENAME 227 #define VIDEOPLAYER_TITLE 250 #define VIDEOPLAYER_GENRE 251 @@ -505,7 +506,7 @@ // the multiple information vector #define MULTI_INFO_START 40000 -#define MULTI_INFO_END 41000 // 1000 references is all we have for now +#define MULTI_INFO_END 49999 #define COMBINED_VALUES_START 100000 // forward @@ -635,6 +636,7 @@ void SetLibraryBool(int condition, bool value); bool GetLibraryBool(int condition); void ResetLibraryBools(); + CStdString LocalizeTime(const CDateTime &time, TIME_FORMAT format) const; protected: // routines for window retrieval @@ -647,7 +649,6 @@ int TranslateListItem(const CStdString &info); int TranslateMusicPlayerString(const CStdString &info) const; TIME_FORMAT TranslateTimeFormat(const CStdString &format); - CStdString LocalizeTime(const CDateTime &time, TIME_FORMAT format) const; bool GetItemBool(const CGUIListItem *item, int condition) const; CStdString VideoWidthToResolutionDescription(int iWidth) const; CStdString VideoAspectToAspectDescription(float fAspect) const;