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/GUIWindowAddonBrowser.cpp | 677 ++++++++++++++++++++++++++++++++++ 1 file changed, 677 insertions(+) create mode 100644 xbmc/addons/GUIWindowAddonBrowser.cpp (limited to 'xbmc/addons/GUIWindowAddonBrowser.cpp') diff --git a/xbmc/addons/GUIWindowAddonBrowser.cpp b/xbmc/addons/GUIWindowAddonBrowser.cpp new file mode 100644 index 0000000..f4560dd --- /dev/null +++ b/xbmc/addons/GUIWindowAddonBrowser.cpp @@ -0,0 +1,677 @@ +/* + * 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 "GUIWindowAddonBrowser.h" +#include "addons/AddonManager.h" +#include "addons/Repository.h" +#include "GUIDialogAddonInfo.h" +#include "GUIDialogAddonSettings.h" +#include "dialogs/GUIDialogBusy.h" +#include "dialogs/GUIDialogOK.h" +#include "dialogs/GUIDialogYesNo.h" +#include "dialogs/GUIDialogSelect.h" +#include "dialogs/GUIDialogFileBrowser.h" +#include "GUIUserMessages.h" +#include "guilib/GUIWindowManager.h" +#include "utils/URIUtils.h" +#include "URL.h" +#include "FileItem.h" +#include "filesystem/File.h" +#include "filesystem/Directory.h" +#include "filesystem/AddonsDirectory.h" +#include "addons/AddonInstaller.h" +#include "utils/JobManager.h" +#include "utils/log.h" +#include "threads/SingleLock.h" +#include "settings/Settings.h" +#include "settings/MediaSourceSettings.h" +#include "utils/StringUtils.h" +#include "AddonDatabase.h" +#include "settings/AdvancedSettings.h" +#include "storage/MediaManager.h" +#include "LangInfo.h" +#include "input/Key.h" +#include "ContextMenuManager.h" + +#define CONTROL_AUTOUPDATE 5 +#define CONTROL_SHUTUP 6 +#define CONTROL_FOREIGNFILTER 7 +#define CONTROL_BROKENFILTER 8 + +using namespace ADDON; +using namespace XFILE; +using namespace std; + +CGUIWindowAddonBrowser::CGUIWindowAddonBrowser(void) +: CGUIMediaWindow(WINDOW_ADDON_BROWSER, "AddonBrowser.xml") +{ +} + +CGUIWindowAddonBrowser::~CGUIWindowAddonBrowser() +{ +} + +bool CGUIWindowAddonBrowser::OnMessage(CGUIMessage& message) +{ + switch ( message.GetMessage() ) + { + case GUI_MSG_WINDOW_DEINIT: + { + if (m_thumbLoader.IsLoading()) + m_thumbLoader.StopThread(); + } + break; + case GUI_MSG_WINDOW_INIT: + { + m_rootDir.AllowNonLocalSources(false); + + // is this the first time the window is opened? + if (m_vecItems->GetPath() == "?" && message.GetStringParam().empty()) + m_vecItems->SetPath(""); + } + break; + case GUI_MSG_CLICKED: + { + int iControl = message.GetSenderId(); + if (iControl == CONTROL_AUTOUPDATE) + { + const CGUIControl *control = GetControl(CONTROL_AUTOUPDATE); + if (control && control->GetControlType() == CGUIControl::GUICONTROL_BUTTON) + CSettings::Get().SetInt("general.addonupdates", (CSettings::Get().GetInt("general.addonupdates")+1) % AUTO_UPDATES_MAX); + else + CSettings::Get().SetInt("general.addonupdates", (CSettings::Get().GetInt("general.addonupdates") == 0) ? 1 : 0); + UpdateButtons(); + return true; + } + else if (iControl == CONTROL_SHUTUP) + { + CSettings::Get().ToggleBool("general.addonnotifications"); + CSettings::Get().Save(); + return true; + } + else if (iControl == CONTROL_FOREIGNFILTER) + { + CSettings::Get().ToggleBool("general.addonforeignfilter"); + CSettings::Get().Save(); + Refresh(); + return true; + } + else if (iControl == CONTROL_BROKENFILTER) + { + CSettings::Get().ToggleBool("general.addonbrokenfilter"); + CSettings::Get().Save(); + Refresh(); + return true; + } + else if (m_viewControl.HasControl(iControl)) // list/thumb control + { + // get selected item + int iItem = m_viewControl.GetSelectedItem(); + int iAction = message.GetParam1(); + + // iItem is checked for validity inside these routines + if (iAction == ACTION_SHOW_INFO) + { + if (!m_vecItems->Get(iItem)->GetProperty("Addon.ID").empty()) + return CGUIDialogAddonInfo::ShowForItem((*m_vecItems)[iItem]); + return false; + } + } + } + break; + case GUI_MSG_NOTIFY_ALL: + { + if (message.GetParam1() == GUI_MSG_UPDATE_ITEM && IsActive() && message.GetNumStringParams() == 1) + { // update this item + for (int i = 0; i < m_vecItems->Size(); ++i) + { + CFileItemPtr item = m_vecItems->Get(i); + if (item->GetProperty("Addon.ID") == message.GetStringParam()) + { + SetItemLabel2(item); + return true; + } + } + } + } + break; + default: + break; + } + return CGUIMediaWindow::OnMessage(message); +} + +void CGUIWindowAddonBrowser::GetContextButtons(int itemNumber, CContextButtons& buttons) +{ + if (itemNumber < 0 || itemNumber >= m_vecItems->Size()) + return; + + CFileItemPtr pItem = m_vecItems->Get(itemNumber); + if (!pItem->IsPath("addons://enabled/")) + buttons.Add(CONTEXT_BUTTON_SCAN,24034); + + AddonPtr addon; + if (!CAddonMgr::Get().GetAddon(pItem->GetProperty("Addon.ID").asString(), addon, ADDON_UNKNOWN, false)) // allow disabled addons + return; + + if (addon->Type() == ADDON_REPOSITORY && pItem->m_bIsFolder) + { + buttons.Add(CONTEXT_BUTTON_SCAN,24034); + buttons.Add(CONTEXT_BUTTON_REFRESH,24035); + } + + buttons.Add(CONTEXT_BUTTON_INFO,24003); + + if (addon->HasSettings()) + buttons.Add(CONTEXT_BUTTON_SETTINGS,24020); + + CContextMenuManager::Get().AddVisibleItems(pItem, buttons); +} + +bool CGUIWindowAddonBrowser::OnContextButton(int itemNumber, + CONTEXT_BUTTON button) +{ + CFileItemPtr pItem = m_vecItems->Get(itemNumber); + if (pItem->IsPath("addons://enabled/")) + { + if (button == CONTEXT_BUTTON_SCAN) + { + CAddonMgr::Get().FindAddons(); + return true; + } + } + + AddonPtr addon; + if (CAddonMgr::Get().GetAddon(pItem->GetProperty("Addon.ID").asString(), addon, ADDON_UNKNOWN, false)) + { + if (button == CONTEXT_BUTTON_SETTINGS) + return CGUIDialogAddonSettings::ShowAndGetInput(addon); + + if (button == CONTEXT_BUTTON_REFRESH) + { + CAddonDatabase database; + database.Open(); + database.DeleteRepository(addon->ID()); + button = CONTEXT_BUTTON_SCAN; + } + + if (button == CONTEXT_BUTTON_SCAN) + { + CAddonInstaller::Get().UpdateRepos(true); + return true; + } + + if (button == CONTEXT_BUTTON_INFO) + { + CGUIDialogAddonInfo::ShowForItem(pItem); + return true; + } + } + + return CGUIMediaWindow::OnContextButton(itemNumber, button); +} + +class UpdateAddons : public IRunnable +{ + virtual void Run() + { + VECADDONS addons; + CAddonMgr::Get().GetAllOutdatedAddons(addons, true); // get local + for (VECADDONS::iterator i = addons.begin(); i != addons.end(); ++i) + { + std::string referer = StringUtils::Format("Referer=%s-%s.zip",(*i)->ID().c_str(),(*i)->Version().asString().c_str()); + CAddonInstaller::Get().Install((*i)->ID(), true, referer); // force install + } + } +}; + +class UpdateRepos : public IRunnable +{ + virtual void Run() + { + CAddonInstaller::Get().UpdateRepos(true, true); + } +}; + +bool CGUIWindowAddonBrowser::OnClick(int iItem) +{ + CFileItemPtr item = m_vecItems->Get(iItem); + if (item->GetPath() == "addons://install/") + { + // pop up filebrowser to grab an installed folder + VECSOURCES shares = *CMediaSourceSettings::Get().GetSources("files"); + g_mediaManager.GetLocalDrives(shares); + g_mediaManager.GetNetworkLocations(shares); + std::string path; + if (CGUIDialogFileBrowser::ShowAndGetFile(shares, "*.zip", g_localizeStrings.Get(24041), path)) + CAddonInstaller::Get().InstallFromZip(path); + return true; + } + else if (item->GetPath() == "addons://check/") + { + // perform the check for updates + UpdateRepos updater; + if (CGUIDialogBusy::Wait(&updater)) + Refresh(); + return true; + } + if (item->GetPath() == "addons://update_all/") + { + // fire off a threaded update of all addons + UpdateAddons updater; + if (CGUIDialogBusy::Wait(&updater)) + return Update("addons://downloading/"); + return true; + } + if (!item->m_bIsFolder) + { + // cancel a downloading job + if (item->HasProperty("Addon.Downloading")) + { + if (CGUIDialogYesNo::ShowAndGetInput(g_localizeStrings.Get(24000), + item->GetProperty("Addon.Name").asString(), + g_localizeStrings.Get(24066),"")) + { + if (CAddonInstaller::Get().Cancel(item->GetProperty("Addon.ID").asString())) + Refresh(); + } + return true; + } + + CGUIDialogAddonInfo::ShowForItem(item); + return true; + } + if (item->IsPath("addons://search/")) + return Update(item->GetPath()); + + return CGUIMediaWindow::OnClick(iItem); +} + +void CGUIWindowAddonBrowser::UpdateButtons() +{ + const CGUIControl *control = GetControl(CONTROL_AUTOUPDATE); + if (control && control->GetControlType() == CGUIControl::GUICONTROL_BUTTON) + { // set label + CSettingInt *setting = (CSettingInt *)CSettings::Get().GetSetting("general.addonupdates"); + if (setting) + { + const StaticIntegerSettingOptions& options = setting->GetOptions(); + for (StaticIntegerSettingOptions::const_iterator it = options.begin(); it != options.end(); ++it) + { + if (it->second == setting->GetValue()) + { + SET_CONTROL_LABEL(CONTROL_AUTOUPDATE, it->first); + break; + } + } + } + } + else + { // old skin with toggle button - set on if auto updates are on + SET_CONTROL_SELECTED(GetID(),CONTROL_AUTOUPDATE, CSettings::Get().GetInt("general.addonupdates") == AUTO_UPDATES_ON); + } + SET_CONTROL_SELECTED(GetID(),CONTROL_SHUTUP, CSettings::Get().GetBool("general.addonnotifications")); + SET_CONTROL_SELECTED(GetID(),CONTROL_FOREIGNFILTER, CSettings::Get().GetBool("general.addonforeignfilter")); + SET_CONTROL_SELECTED(GetID(),CONTROL_BROKENFILTER, CSettings::Get().GetBool("general.addonbrokenfilter")); + CGUIMediaWindow::UpdateButtons(); +} + +static bool FilterVar(bool valid, const CVariant& variant, + const std::string& check) +{ + if (!valid) + return false; + + if (variant.isNull() || variant.asString().empty()) + return false; + + std::string regions = variant.asString(); + return regions.find(check) == std::string::npos; +} + +bool CGUIWindowAddonBrowser::GetDirectory(const std::string& strDirectory, + CFileItemList& items) +{ + bool result; + if (URIUtils::PathEquals(strDirectory, "addons://downloading/")) + { + VECADDONS addons; + CAddonInstaller::Get().GetInstallList(addons); + + CURL url(strDirectory); + CAddonsDirectory::GenerateListing(url,addons,items); + result = true; + items.SetProperty("reponame",g_localizeStrings.Get(24067)); + items.SetPath(strDirectory); + + if (m_guiState.get() && !m_guiState->HideParentDirItems()) + { + CFileItemPtr pItem(new CFileItem("..")); + pItem->SetPath(m_history.GetParentPath()); + pItem->m_bIsFolder = true; + pItem->m_bIsShareOrDrive = false; + items.AddFront(pItem, 0); + } + + } + else + { + result = CGUIMediaWindow::GetDirectory(strDirectory,items); + if (CSettings::Get().GetBool("general.addonforeignfilter")) + { + int i=0; + while (i < items.Size()) + { + if (!FilterVar(true, items[i]->GetProperty("Addon.Language"), "en") || + !FilterVar(true, items[i]->GetProperty("Addon.Language"), g_langInfo.GetLanguageLocale())) + { + i++; + } + else + items.Remove(i); + } + } + if (CSettings::Get().GetBool("general.addonbrokenfilter")) + { + for (int i = items.Size() - 1; i >= 0; i--) + { + if (!items[i]->GetProperty("Addon.Broken").empty()) + { //check if it's installed + AddonPtr addon; + if (!CAddonMgr::Get().GetAddon(items[i]->GetProperty("Addon.ID").asString(), addon)) + items.Remove(i); + } + } + } + } + + if (strDirectory.empty() && CAddonInstaller::Get().IsDownloading()) + { + CFileItemPtr item(new CFileItem("addons://downloading/",true)); + item->SetLabel(g_localizeStrings.Get(24067)); + item->SetLabelPreformated(true); + item->SetIconImage("DefaultNetwork.png"); + items.Add(item); + } + + items.SetContent("addons"); + + for (int i=0;im_bIsFolder) return; + unsigned int percent; + if (CAddonInstaller::Get().GetProgress(item->GetProperty("Addon.ID").asString(), percent)) + { + std::string progress = StringUtils::Format(g_localizeStrings.Get(24042).c_str(), percent); + item->SetProperty("Addon.Status", progress); + item->SetProperty("Addon.Downloading", true); + } + else + item->ClearProperty("Addon.Downloading"); + item->SetLabel2(item->GetProperty("Addon.Status").asString()); + // to avoid the view state overriding label 2 + item->SetLabelPreformated(true); +} + +bool CGUIWindowAddonBrowser::Update(const std::string &strDirectory, bool updateFilterPath /* = true */) +{ + if (m_thumbLoader.IsLoading()) + m_thumbLoader.StopThread(); + + if (!CGUIMediaWindow::Update(strDirectory, updateFilterPath)) + return false; + + m_thumbLoader.Load(*m_vecItems); + + return true; +} + +int CGUIWindowAddonBrowser::SelectAddonID(TYPE type, std::string &addonID, bool showNone /* = false */, bool showDetails /* = true */, bool showInstalled /* = true */, bool showInstallable /*= false */, bool showMore /* = true */) +{ + vector types; + types.push_back(type); + return SelectAddonID(types, addonID, showNone, showDetails, showInstalled, showInstallable, showMore); +} + +int CGUIWindowAddonBrowser::SelectAddonID(ADDON::TYPE type, vector &addonIDs, bool showNone /* = false */, bool showDetails /* = true */, bool multipleSelection /* = true */, bool showInstalled /* = true */, bool showInstallable /* = false */, bool showMore /* = true */) +{ + vector types; + types.push_back(type); + return SelectAddonID(types, addonIDs, showNone, showDetails, multipleSelection, showInstalled, showInstallable, showMore); +} + +int CGUIWindowAddonBrowser::SelectAddonID(const vector &types, std::string &addonID, bool showNone /* = false */, bool showDetails /* = true */, bool showInstalled /* = true */, bool showInstallable /* = false */, bool showMore /* = true */) +{ + vector addonIDs; + if (!addonID.empty()) + addonIDs.push_back(addonID); + int retval = SelectAddonID(types, addonIDs, showNone, showDetails, false, showInstalled, showInstallable, showMore); + if (addonIDs.size() > 0) + addonID = addonIDs.at(0); + else + addonID = ""; + return retval; +} + +int CGUIWindowAddonBrowser::SelectAddonID(const vector &types, vector &addonIDs, bool showNone /* = false */, bool showDetails /* = true */, bool multipleSelection /* = true */, bool showInstalled /* = true */, bool showInstallable /* = false */, bool showMore /* = true */) +{ + // if we shouldn't show neither installed nor installable addons the list will be empty + if (!showInstalled && !showInstallable) + return 0; + + // can't show the "Get More" button if we already show installable addons + if (showInstallable) + showMore = false; + + CGUIDialogSelect *dialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); + if (!dialog) + return 0; + + // get rid of any invalid addon types + vector validTypes(types.size()); + std::copy_if(types.begin(), types.end(), validTypes.begin(), [](ADDON::TYPE type) { return type != ADDON_UNKNOWN; }); + + if (validTypes.empty()) + return 0; + + // get all addons to show + VECADDONS addons; + if (showInstalled) + { + for (vector::const_iterator type = validTypes.begin(); type != validTypes.end(); ++type) + { + VECADDONS typeAddons; + if (*type == ADDON_AUDIO) + CAddonsDirectory::GetScriptsAndPlugins("audio", typeAddons); + else if (*type == ADDON_EXECUTABLE) + CAddonsDirectory::GetScriptsAndPlugins("executable", typeAddons); + else if (*type == ADDON_IMAGE) + CAddonsDirectory::GetScriptsAndPlugins("image", typeAddons); + else if (*type == ADDON_VIDEO) + CAddonsDirectory::GetScriptsAndPlugins("video", typeAddons); + else + CAddonMgr::Get().GetAddons(*type, typeAddons); + + addons.insert(addons.end(), typeAddons.begin(), typeAddons.end()); + } + } + + if (showInstallable || showMore) + { + VECADDONS installableAddons; + CAddonDatabase database; + if (database.Open() && database.GetAddons(installableAddons)) + { + for (ADDON::IVECADDONS addon = installableAddons.begin(); addon != installableAddons.end();) + { + AddonPtr pAddon = *addon; + + // check if the addon matches one of the provided addon types + bool matchesType = false; + for (vector::const_iterator type = validTypes.begin(); type != validTypes.end(); ++type) + { + if (pAddon->IsType(*type)) + { + matchesType = true; + break; + } + } + + // only show addons that match one of the provided addon types and that aren't disabled + if (matchesType && !CAddonMgr::Get().IsAddonDisabled(pAddon->ID())) + { + // check if the addon is installed + bool isInstalled = CAddonMgr::Get().IsAddonInstalled(pAddon->ID()); + + // check if the addon is installed or can be installed + if ((showInstallable || showMore) && !isInstalled && CAddonMgr::Get().CanAddonBeInstalled(pAddon)) + { + ++addon; + continue; + } + } + + addon = installableAddons.erase(addon); + } + + if (showInstallable) + addons.insert(addons.end(), installableAddons.begin(), installableAddons.end()); + else if (showMore) + showMore = !installableAddons.empty(); + } + } + + if (addons.empty() && !showNone) + return 0; + + // turn the addons into items + std::map addonMap; + CFileItemList items; + for (ADDON::IVECADDONS addon = addons.begin(); addon != addons.end(); ++addon) + { + CFileItemPtr item(CAddonsDirectory::FileItemFromAddon(*addon, "")); + if (!items.Contains(item->GetPath())) + { + items.Add(item); + addonMap.insert(std::make_pair(item->GetPath(), *addon)); + } + } + + if (items.IsEmpty() && !showNone) + return 0; + + std::string heading; + for (vector::const_iterator type = validTypes.begin(); type != validTypes.end(); ++type) + { + if (!heading.empty()) + heading += ", "; + heading += TranslateType(*type, true); + } + + dialog->SetHeading(heading); + dialog->Reset(); + dialog->SetUseDetails(showDetails); + + if (multipleSelection) + { + showNone = false; + showMore = false; + dialog->EnableButton(true, 186); + } + else if (showMore) + dialog->EnableButton(true, 21452); + + if (showNone) + { + CFileItemPtr item(new CFileItem("", false)); + item->SetLabel(g_localizeStrings.Get(231)); + item->SetLabel2(g_localizeStrings.Get(24040)); + item->SetIconImage("DefaultAddonNone.png"); + item->SetSpecialSort(SortSpecialOnTop); + items.Add(item); + } + items.Sort(SortByLabel, SortOrderAscending); + + if (addonIDs.size() > 0) + { + for (vector::const_iterator it = addonIDs.begin(); it != addonIDs.end() ; ++it) + { + CFileItemPtr item = items.Get(*it); + if (item) + item->Select(true); + } + } + dialog->SetItems(&items); + dialog->SetMultiSelection(multipleSelection); + dialog->DoModal(); + + // if the "Get More" button has been pressed and we haven't shown the + // installable addons so far show a list of installable addons + if (showMore&& dialog->IsButtonPressed()) + return SelectAddonID(types, addonIDs, showNone, showDetails, multipleSelection, false, true, false); + + if (!dialog->IsConfirmed()) + return 0; + + addonIDs.clear(); + const CFileItemList& list = dialog->GetSelectedItems(); + for (int i = 0 ; i < list.Size() ; i++) + { + const CFileItemPtr& item = list.Get(i); + + // check if one of the selected addons needs to be installed + if (showInstallable) + { + std::map::const_iterator itAddon = addonMap.find(item->GetPath()); + if (itAddon != addonMap.end()) + { + const AddonPtr& addon = itAddon->second; + + // if the addon isn't installed we need to install it + if (!CAddonMgr::Get().IsAddonInstalled(addon->ID())) + { + AddonPtr installedAddon; + if (!CAddonInstaller::Get().InstallModal(addon->ID(), installedAddon, false)) + continue; + } + + // if the addon is disabled we need to enable it + if (CAddonMgr::Get().IsAddonDisabled(addon->ID())) + CAddonMgr::Get().DisableAddon(addon->ID(), false); + } + } + + addonIDs.push_back(item->GetPath()); + } + return 1; +} + +std::string CGUIWindowAddonBrowser::GetStartFolder(const std::string &dir) +{ + if (URIUtils::PathStarts(dir, "addons://")) + return dir; + return CGUIMediaWindow::GetStartFolder(dir); +} -- cgit v1.2.3