diff options
author | Fice <fice@arcor.de> | 2013-10-06 14:22:46 +0200 |
---|---|---|
committer | Thomas Amland <thomas.amland@gmail.com> | 2015-03-02 10:57:48 +0100 |
commit | b30c551b4769e3f53e091314ddf7fe8b042302ce (patch) | |
tree | 4b3d7bc3eeb33de7bc5e5531139af1766d69d4dc | |
parent | 295106877608238f7874040d21dc29e0b63d90e7 (diff) |
[ADDONS] Context Menu Addons System
-rw-r--r-- | addons/xbmc.python/addon.xml | 1 | ||||
-rw-r--r-- | addons/xbmc.python/contextitem.xsd | 29 | ||||
-rw-r--r-- | language/English/strings.po | 8 | ||||
-rw-r--r-- | xbmc/ContextMenuManager.cpp | 116 | ||||
-rw-r--r-- | xbmc/ContextMenuManager.h | 78 | ||||
-rw-r--r-- | xbmc/Makefile.in | 1 | ||||
-rw-r--r-- | xbmc/addons/Addon.cpp | 3 | ||||
-rw-r--r-- | xbmc/addons/Addon.h | 3 | ||||
-rw-r--r-- | xbmc/addons/AddonDatabase.cpp | 7 | ||||
-rw-r--r-- | xbmc/addons/AddonManager.cpp | 5 | ||||
-rw-r--r-- | xbmc/addons/ContextItemAddon.cpp | 108 | ||||
-rw-r--r-- | xbmc/addons/ContextItemAddon.h | 72 | ||||
-rw-r--r-- | xbmc/addons/IAddon.h | 1 | ||||
-rw-r--r-- | xbmc/addons/Makefile | 1 | ||||
-rw-r--r-- | xbmc/dialogs/GUIDialogContextMenu.h | 6 |
15 files changed, 434 insertions, 5 deletions
diff --git a/addons/xbmc.python/addon.xml b/addons/xbmc.python/addon.xml index 1eccd4284b..b5530fe74c 100644 --- a/addons/xbmc.python/addon.xml +++ b/addons/xbmc.python/addon.xml @@ -10,4 +10,5 @@ <extension-point id="weather" schema="script.xsd"/> <extension-point id="library" schema="script.xsd"/> <extension-point id="plugin" schema="pluginsource.xsd"/> + <extension-point id="context.item" schema="contextitem.xsd"/> </addon> diff --git a/addons/xbmc.python/contextitem.xsd b/addons/xbmc.python/contextitem.xsd new file mode 100644 index 0000000000..3c7c671528 --- /dev/null +++ b/addons/xbmc.python/contextitem.xsd @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE schema PUBLIC "-//W3C//DTD XMLSCHEMA 200102//EN" "http://www.w3.org/2001/XMLSchema.dtd"> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:element name="extension"> + <xs:complexType> + <xs:sequence> + <xs:element name="item"> + <xs:complexType> + <xs:sequence> + <xs:element name="label" type="xs:string"/> + <xs:element name="visible" type="xs:string"/> + <xs:element name="parent" type="xs:string"/> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="point" type="xs:string" use="required"/> + <xs:attribute name="id" type="simpleIdentifier"/> + <xs:attribute name="name" type="xs:string"/> + <xs:attribute name="library" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> + <xs:simpleType name="simpleIdentifier"> + <xs:restriction base="xs:string"> + <xs:pattern value="[^.]+"/> + </xs:restriction> + </xs:simpleType> +</xs:schema> + diff --git a/language/English/strings.po b/language/English/strings.po index 717356a773..c3c8412732 100644 --- a/language/English/strings.po +++ b/language/English/strings.po @@ -12307,7 +12307,13 @@ msgctxt "#24024" msgid "Add-on disabled" msgstr "" -#empty strings from id 24025 to 24026 +#. Used as the type name for context item addons +#: xbmc/addons/Addons.cpp +msgctxt "#24025" +msgid "Context Items" +msgstr "" + +#empty string with id 24026 #: xbmc/addons/Addon.cpp msgctxt "#24027" diff --git a/xbmc/ContextMenuManager.cpp b/xbmc/ContextMenuManager.cpp new file mode 100644 index 0000000000..127f29fff9 --- /dev/null +++ b/xbmc/ContextMenuManager.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2013-2015 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 + * <http://www.gnu.org/licenses/>. + * + */ + +#include "ContextMenuManager.h" +#include "addons/Addon.h" +#include "addons/AddonManager.h" +#include "addons/ContextItemAddon.h" +#include "addons/IAddon.h" +#include "interfaces/generic/ScriptInvocationManager.h" +#include "interfaces/python/ContextItemAddonInvoker.h" +#include "interfaces/python/XBPython.h" +#include "Util.h" +#include "utils/log.h" +#include "video/dialogs/GUIDialogVideoInfo.h" + +using namespace ADDON; + +typedef std::map<unsigned int, ContextItemAddonPtr>::value_type ValueType; + + +CContextMenuManager::CContextMenuManager() + : m_iCurrentContextId(CONTEXT_BUTTON_FIRST_ADDON) +{ + Init(); +} + +CContextMenuManager& CContextMenuManager::Get() +{ + static CContextMenuManager mgr; + return mgr; +} + +void CContextMenuManager::Init() +{ + //Make sure we load all context items on first usage... + VECADDONS addons; + if (CAddonMgr::Get().GetAddons(ADDON_CONTEXT_ITEM, addons)) + { + for (const auto& addon : addons) + Register(std::static_pointer_cast<CContextItemAddon>(addon)); + } +} + +void CContextMenuManager::Register(const ContextItemAddonPtr& cm) +{ + if (!cm) + return; + m_contextAddons[m_iCurrentContextId++] = cm; +} + +bool CContextMenuManager::Unregister(const ContextItemAddonPtr& cm) +{ + if (!cm) + return false; + + auto it = std::find_if(m_contextAddons.begin(), m_contextAddons.end(), + [&](const ValueType& value){ return value.second->ID() == cm->ID(); }); + + if (it != m_contextAddons.end()) + { + m_contextAddons.erase(it); + return true; + } + return false; +} + +ContextItemAddonPtr CContextMenuManager::GetContextItemByID(unsigned int id) +{ + auto it = m_contextAddons.find(id); + if (it != m_contextAddons.end()) + return it->second; + return ContextItemAddonPtr(); +} + +void CContextMenuManager::AddVisibleItems(const CFileItemPtr& item, CContextButtons& list, const std::string& parent /* = "" */) +{ + if (!item) + return; + + for (const auto& kv : m_contextAddons) + { + if (kv.second->GetParent() == parent && kv.second->IsVisible(item)) + list.push_back(std::make_pair(kv.first, kv.second->GetLabel())); + } +} + +bool CContextMenuManager::Execute(unsigned int id, const CFileItemPtr& item) +{ + if (!item) + return false; + + const ContextItemAddonPtr addon = GetContextItemByID(id); + if (!addon || !addon->IsVisible(item)) + return false; + + LanguageInvokerPtr invoker(new CContextItemAddonInvoker(&g_pythonParser, item)); + return (CScriptInvocationManager::Get().ExecuteAsync(addon->LibPath(), invoker, addon) != -1); +} + diff --git a/xbmc/ContextMenuManager.h b/xbmc/ContextMenuManager.h new file mode 100644 index 0000000000..2dff9dce87 --- /dev/null +++ b/xbmc/ContextMenuManager.h @@ -0,0 +1,78 @@ +#pragma once +/* + * Copyright (C) 2013-2015 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 + * <http://www.gnu.org/licenses/>. + * + */ + +#include <map> +#include "addons/ContextItemAddon.h" +#include "dialogs/GUIDialogContextMenu.h" + +#define CONTEXT_MENU_GROUP_MANAGE "kodi.core.manage" + +class CContextMenuManager +{ +public: + static CContextMenuManager& Get(); + + /*! + * \brief Executes a context menu item. + * \param id - id of the context button to execute. + * \param item - the currently selected item. + * \return true if executed successfully, false otherwise + */ + bool Execute(unsigned int id, const CFileItemPtr& item); + + /*! + * \brief Adds all registered context item to the list. + * \param item - the currently selected item. + * \param list - the context menu. + * \param parent - the ID of the context menu. Empty string if the root menu. + * CONTEXT_MENU_GROUP_MANAGE if the 'manage' submenu. + */ + void AddVisibleItems(const CFileItemPtr& item, CContextButtons& list, const std::string& parent = ""); + + /*! + * \brief Adds a context item to this manager. + * NOTE: only 'enabled' context addons should be added. + */ + void Register(const ADDON::ContextItemAddonPtr& cm); + + /*! + * \brief Removes a context addon from this manager. + */ + bool Unregister(const ADDON::ContextItemAddonPtr& cm); + +private: + CContextMenuManager(); + CContextMenuManager(const CContextMenuManager&); + CContextMenuManager const& operator=(CContextMenuManager const&); + virtual ~CContextMenuManager() {} + + void Init(); + + /*! + * \brief Get a context menu item by its assigned id. + * \param id - the button id of the context item. + * \return the addon or NULL if no item with given id is registered. + */ + ADDON::ContextItemAddonPtr GetContextItemByID(const unsigned int id); + + std::map<unsigned int, ADDON::ContextItemAddonPtr> m_contextAddons; + unsigned int m_iCurrentContextId; +}; diff --git a/xbmc/Makefile.in b/xbmc/Makefile.in index 86a9bd16a5..c95680118e 100644 --- a/xbmc/Makefile.in +++ b/xbmc/Makefile.in @@ -5,6 +5,7 @@ SRCS=Application.cpp \ Autorun.cpp \ AutoSwitch.cpp \ BackgroundInfoLoader.cpp \ + ContextMenuManager.cpp \ CompileInfo.cpp \ CueDocument.cpp \ DatabaseManager.cpp \ diff --git a/xbmc/addons/Addon.cpp b/xbmc/addons/Addon.cpp index 2def23005f..2aa849f87b 100644 --- a/xbmc/addons/Addon.cpp +++ b/xbmc/addons/Addon.cpp @@ -80,6 +80,7 @@ static const TypeMapping types[] = {"xbmc.python.library", ADDON_SCRIPT_LIBRARY, 24081, "DefaultAddonHelper.png" }, {"xbmc.python.module", ADDON_SCRIPT_MODULE, 24082, "DefaultAddonLibrary.png" }, {"xbmc.subtitle.module", ADDON_SUBTITLE_MODULE, 24012, "DefaultAddonSubtitles.png" }, + {"kodi.context.item", ADDON_CONTEXT_ITEM, 24025, "DefaultAddonContextItem.png" }, {"xbmc.gui.skin", ADDON_SKIN, 166, "DefaultAddonSkin.png" }, {"xbmc.webinterface", ADDON_WEB_INTERFACE, 199, "DefaultAddonWebSkin.png" }, {"xbmc.addon.repository", ADDON_REPOSITORY, 24011, "DefaultAddonRepository.png" }, @@ -360,6 +361,7 @@ void CAddon::BuildLibName(const cp_extension_t *extension) case ADDON_SUBTITLE_MODULE: case ADDON_PLUGIN: case ADDON_SERVICE: + case ADDON_CONTEXT_ITEM: ext = ADDON_PYTHON_EXT; break; default: @@ -394,6 +396,7 @@ void CAddon::BuildLibName(const cp_extension_t *extension) case ADDON_SERVICE: case ADDON_REPOSITORY: case ADDON_AUDIOENCODER: + case ADDON_CONTEXT_ITEM: { std::string temp = CAddonMgr::Get().GetExtValue(extension->configuration, "@library"); m_strLibName = temp; diff --git a/xbmc/addons/Addon.h b/xbmc/addons/Addon.h index 28d8eef844..00e92f6978 100644 --- a/xbmc/addons/Addon.h +++ b/xbmc/addons/Addon.h @@ -236,6 +236,7 @@ protected: bool m_settingsLoaded; bool m_userSettingsLoaded; + virtual void ClearStrings(); private: friend class CAddonMgr; AddonProps m_props; @@ -248,7 +249,7 @@ private: void Disable() { m_enabled = false; ClearStrings();} virtual bool LoadStrings(); - virtual void ClearStrings(); + bool m_hasStrings; bool m_checkedStrings; bool m_hasSettings; diff --git a/xbmc/addons/AddonDatabase.cpp b/xbmc/addons/AddonDatabase.cpp index 6803aa5905..69b47eafce 100644 --- a/xbmc/addons/AddonDatabase.cpp +++ b/xbmc/addons/AddonDatabase.cpp @@ -25,6 +25,7 @@ #include "utils/StringUtils.h" #include "XBDateTime.h" #include "dbwrappers/dataset.h" +#include "addons/ContextItemAddon.h" using namespace ADDON; using namespace std; @@ -620,7 +621,8 @@ bool CAddonDatabase::DisableAddon(const std::string &addonID, bool disable /* = // If the addon is a special, call the disabled handler AddonPtr addon; if ((CAddonMgr::Get().GetAddon(addonID, addon, ADDON_SERVICE, false) - || CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false)) && addon) + || CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false) + || CAddonMgr::Get().GetAddon(addonID, addon, ADDON_CONTEXT_ITEM, false)) && addon) addon->OnDisabled(); return true; @@ -638,7 +640,8 @@ bool CAddonDatabase::DisableAddon(const std::string &addonID, bool disable /* = // If the addon is a special, call the enabled handler AddonPtr addon; if ((CAddonMgr::Get().GetAddon(addonID, addon, ADDON_SERVICE, false) - || CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false)) && addon) + || CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false) + || CAddonMgr::Get().GetAddon(addonID, addon, ADDON_CONTEXT_ITEM, false)) && addon) addon->OnEnabled(); } } diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp index 471fa846f1..b1c31b3670 100644 --- a/xbmc/addons/AddonManager.cpp +++ b/xbmc/addons/AddonManager.cpp @@ -47,6 +47,7 @@ #include "Repository.h" #include "Skin.h" #include "Service.h" +#include "ContextItemAddon.h" #include "Util.h" #include "addons/Webinterface.h" @@ -173,6 +174,8 @@ AddonPtr CAddonMgr::Factory(const cp_extension_t *props) return AddonPtr(new CAddonLibrary(props)); case ADDON_REPOSITORY: return AddonPtr(new CRepository(props)); + case ADDON_CONTEXT_ITEM: + return AddonPtr(new CContextItemAddon(props)); default: break; } @@ -682,6 +685,8 @@ AddonPtr CAddonMgr::AddonFromProps(AddonProps& addonProps) return AddonPtr(new CAudioEncoder(addonProps)); case ADDON_REPOSITORY: return AddonPtr(new CRepository(addonProps)); + case ADDON_CONTEXT_ITEM: + return AddonPtr(new CContextItemAddon(addonProps)); default: break; } diff --git a/xbmc/addons/ContextItemAddon.cpp b/xbmc/addons/ContextItemAddon.cpp new file mode 100644 index 0000000000..4222936df9 --- /dev/null +++ b/xbmc/addons/ContextItemAddon.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2013-2015 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 + * <http://www.gnu.org/licenses/>. + * + */ + +#include "ContextItemAddon.h" +#include "AddonManager.h" +#include "ContextMenuManager.h" +#include "dialogs/GUIDialogContextMenu.h" +#include "GUIInfoManager.h" +#include "interfaces/info/InfoBool.h" +#include "utils/log.h" +#include "utils/StringUtils.h" +#include "video/dialogs/GUIDialogVideoInfo.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace ADDON +{ + +CContextItemAddon::CContextItemAddon(const AddonProps &props) + : CAddon(props) +{ } + +CContextItemAddon::~CContextItemAddon() +{ } + +CContextItemAddon::CContextItemAddon(const cp_extension_t *ext) + : CAddon(ext) +{ + ELEMENTS items; + if (CAddonMgr::Get().GetExtElements(ext->configuration, "item", items)) + { + cp_cfg_element_t *item = items[0]; + + m_label = CAddonMgr::Get().GetExtValue(item, "label"); + if (StringUtils::IsNaturalNumber(m_label)) + { + m_label = GetString(boost::lexical_cast<int>(m_label.c_str())); + ClearStrings(); + } + + m_parent = CAddonMgr::Get().GetExtValue(item, "parent"); + + string visible = CAddonMgr::Get().GetExtValue(item, "visible"); + if (visible.empty()) + visible = "false"; + + m_visCondition = g_infoManager.Register(visible, 0); + } +} + +bool CContextItemAddon::OnPreInstall() +{ + return CContextMenuManager::Get().Unregister(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this())); +} + +void CContextItemAddon::OnPostInstall(bool restart, bool update) +{ + if (restart) + { + // need to grab the local addon so we have the correct library path to run + AddonPtr localAddon; + if (CAddonMgr::Get().GetAddon(ID(), localAddon, ADDON_CONTEXT_ITEM)) + { + ContextItemAddonPtr contextItem = std::dynamic_pointer_cast<CContextItemAddon>(localAddon); + if (contextItem) + CContextMenuManager::Get().Register(contextItem); + } + } +} + +void CContextItemAddon::OnPreUnInstall() +{ + CContextMenuManager::Get().Unregister(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this())); +} + +void CContextItemAddon::OnDisabled() +{ + CContextMenuManager::Get().Unregister(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this())); +} +void CContextItemAddon::OnEnabled() +{ + CContextMenuManager::Get().Register(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this())); +} + +bool CContextItemAddon::IsVisible(const CFileItemPtr& item) const +{ + return item && m_visCondition->Get(item.get()); +} + +} diff --git a/xbmc/addons/ContextItemAddon.h b/xbmc/addons/ContextItemAddon.h new file mode 100644 index 0000000000..628fdcd9ce --- /dev/null +++ b/xbmc/addons/ContextItemAddon.h @@ -0,0 +1,72 @@ +#pragma once +/* + * Copyright (C) 2013-2015 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 + * <http://www.gnu.org/licenses/>. + * + */ + +#include <list> +#include <memory> +#include "Addon.h" + +class CFileItem; +typedef std::shared_ptr<CFileItem> CFileItemPtr; + +namespace INFO +{ + class InfoBool; + typedef std::shared_ptr<InfoBool> InfoPtr; +} + +namespace ADDON +{ + class CContextItemAddon : public CAddon + { + public: + CContextItemAddon(const cp_extension_t *ext); + CContextItemAddon(const AddonProps &props); + virtual ~CContextItemAddon(); + + const std::string& GetLabel() const { return m_label; } + + /*! + * \brief Get the parent category of this context item. + * + * \details Returns empty string if at root level or + * CONTEXT_MENU_GROUP_MANAGE when it should be in the 'manage' submenu. + */ + const std::string& GetParent() const { return m_parent; } + + /*! + * \brief Returns true if this contex menu should be visible for given item. + */ + bool IsVisible(const CFileItemPtr& item) const; + + virtual bool OnPreInstall(); + virtual void OnPostInstall(bool restart, bool update); + virtual void OnPreUnInstall(); + virtual void OnDisabled(); + virtual void OnEnabled(); + + private: + std::string m_label; + std::string m_parent; + INFO::InfoPtr m_visCondition; + }; + + typedef std::shared_ptr<CContextItemAddon> ContextItemAddonPtr; +} diff --git a/xbmc/addons/IAddon.h b/xbmc/addons/IAddon.h index 4da99ebd1c..425482fe5e 100644 --- a/xbmc/addons/IAddon.h +++ b/xbmc/addons/IAddon.h @@ -50,6 +50,7 @@ namespace ADDON ADDON_WEB_INTERFACE, ADDON_SERVICE, ADDON_AUDIOENCODER, + ADDON_CONTEXT_ITEM, ADDON_VIDEO, // virtual addon types ADDON_AUDIO, ADDON_IMAGE, diff --git a/xbmc/addons/Makefile b/xbmc/addons/Makefile index 1dbf62e64e..4cf5b17c4d 100644 --- a/xbmc/addons/Makefile +++ b/xbmc/addons/Makefile @@ -10,6 +10,7 @@ SRCS=Addon.cpp \ AddonStatusHandler.cpp \ AddonVersion.cpp \ AudioEncoder.cpp \ + ContextItemAddon.cpp \ GUIDialogAddonInfo.cpp \ GUIDialogAddonSettings.cpp \ GUIViewStateAddonBrowser.cpp \ diff --git a/xbmc/dialogs/GUIDialogContextMenu.h b/xbmc/dialogs/GUIDialogContextMenu.h index ce0c2b7b86..0d2a8cc881 100644 --- a/xbmc/dialogs/GUIDialogContextMenu.h +++ b/xbmc/dialogs/GUIDialogContextMenu.h @@ -140,7 +140,11 @@ enum CONTEXT_BUTTON { CONTEXT_BUTTON_CANCELLED = 0, CONTEXT_BUTTON_USER7, CONTEXT_BUTTON_USER8, CONTEXT_BUTTON_USER9, - CONTEXT_BUTTON_USER10 + CONTEXT_BUTTON_USER10, + + //NOTE: this has to be the last in this enum, + //because this one, and the ones higher will be used by context addons + CONTEXT_BUTTON_FIRST_ADDON }; class CContextButtons : public std::vector< std::pair<unsigned int, std::string> > |