[windows] Fix MAC Address Discovery
[xbmc.git] / xbmc / ContextMenuManager.cpp
blob726611912066c74c38b0b656e98da54495edc214
1 /*
2 * Copyright (C) 2013-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "ContextMenuManager.h"
11 #include "ContextMenuItem.h"
12 #include "ContextMenus.h"
13 #include "FileItem.h"
14 #include "ServiceBroker.h"
15 #include "addons/Addon.h"
16 #include "addons/AddonEvents.h"
17 #include "addons/AddonManager.h"
18 #include "addons/ContextMenuAddon.h"
19 #include "addons/ContextMenus.h"
20 #include "addons/IAddon.h"
21 #include "addons/addoninfo/AddonType.h"
22 #include "dialogs/GUIDialogContextMenu.h"
23 #include "favourites/ContextMenus.h"
24 #include "messaging/ApplicationMessenger.h"
25 #include "music/ContextMenus.h"
26 #include "pvr/PVRContextMenus.h"
27 #include "utils/StringUtils.h"
28 #include "utils/log.h"
29 #include "video/ContextMenus.h"
31 #include <algorithm>
32 #include <iterator>
33 #include <mutex>
35 using namespace ADDON;
36 using namespace PVR;
38 const CContextMenuItem CContextMenuManager::MAIN = CContextMenuItem::CreateGroup("", "", "kodi.core.main", "");
39 const CContextMenuItem CContextMenuManager::MANAGE = CContextMenuItem::CreateGroup("", "", "kodi.core.manage", "");
42 CContextMenuManager::CContextMenuManager(CAddonMgr& addonMgr)
43 : m_addonMgr(addonMgr) {}
45 CContextMenuManager::~CContextMenuManager()
47 Deinit();
50 void CContextMenuManager::Deinit()
52 CPVRContextMenuManager::GetInstance().Events().Unsubscribe(this);
53 m_addonMgr.Events().Unsubscribe(this);
54 m_items.clear();
57 void CContextMenuManager::Init()
59 m_addonMgr.Events().Subscribe(this, &CContextMenuManager::OnEvent);
60 CPVRContextMenuManager::GetInstance().Events().Subscribe(this, &CContextMenuManager::OnPVREvent);
62 std::unique_lock<CCriticalSection> lock(m_criticalSection);
63 m_items = {
64 std::make_shared<CONTEXTMENU::CVideoBrowse>(),
65 std::make_shared<CONTEXTMENU::CVideoChooseVersion>(),
66 std::make_shared<CONTEXTMENU::CVideoPlayVersionUsing>(),
67 std::make_shared<CONTEXTMENU::CVideoResume>(),
68 std::make_shared<CONTEXTMENU::CVideoPlay>(),
69 std::make_shared<CONTEXTMENU::CVideoPlayUsing>(),
70 std::make_shared<CONTEXTMENU::CVideoPlayAndQueue>(),
71 std::make_shared<CONTEXTMENU::CVideoPlayNext>(),
72 std::make_shared<CONTEXTMENU::CVideoQueue>(),
73 std::make_shared<CONTEXTMENU::CMusicBrowse>(),
74 std::make_shared<CONTEXTMENU::CMusicPlay>(),
75 std::make_shared<CONTEXTMENU::CMusicPlayUsing>(),
76 std::make_shared<CONTEXTMENU::CMusicPlayNext>(),
77 std::make_shared<CONTEXTMENU::CMusicQueue>(),
78 std::make_shared<CONTEXTMENU::CAddonInfo>(),
79 std::make_shared<CONTEXTMENU::CEnableAddon>(),
80 std::make_shared<CONTEXTMENU::CDisableAddon>(),
81 std::make_shared<CONTEXTMENU::CAddonSettings>(),
82 std::make_shared<CONTEXTMENU::CCheckForUpdates>(),
83 std::make_shared<CONTEXTMENU::CEpisodeInfo>(),
84 std::make_shared<CONTEXTMENU::CMovieInfo>(),
85 std::make_shared<CONTEXTMENU::CMovieSetInfo>(),
86 std::make_shared<CONTEXTMENU::CMusicVideoInfo>(),
87 std::make_shared<CONTEXTMENU::CTVShowInfo>(),
88 std::make_shared<CONTEXTMENU::CSeasonInfo>(),
89 std::make_shared<CONTEXTMENU::CAlbumInfo>(),
90 std::make_shared<CONTEXTMENU::CArtistInfo>(),
91 std::make_shared<CONTEXTMENU::CSongInfo>(),
92 std::make_shared<CONTEXTMENU::CVideoMarkWatched>(),
93 std::make_shared<CONTEXTMENU::CVideoMarkUnWatched>(),
94 std::make_shared<CONTEXTMENU::CVideoRemoveResumePoint>(),
95 std::make_shared<CONTEXTMENU::CEjectDisk>(),
96 std::make_shared<CONTEXTMENU::CEjectDrive>(),
97 std::make_shared<CONTEXTMENU::CFavouritesTargetBrowse>(),
98 std::make_shared<CONTEXTMENU::CFavouritesTargetResume>(),
99 std::make_shared<CONTEXTMENU::CFavouritesTargetPlay>(),
100 std::make_shared<CONTEXTMENU::CFavouritesTargetInfo>(),
101 std::make_shared<CONTEXTMENU::CMoveUpFavourite>(),
102 std::make_shared<CONTEXTMENU::CMoveDownFavourite>(),
103 std::make_shared<CONTEXTMENU::CChooseThumbnailForFavourite>(),
104 std::make_shared<CONTEXTMENU::CRenameFavourite>(),
105 std::make_shared<CONTEXTMENU::CRemoveFavourite>(),
106 std::make_shared<CONTEXTMENU::CAddRemoveFavourite>(),
107 std::make_shared<CONTEXTMENU::CFavouritesTargetContextMenu>(),
110 ReloadAddonItems();
112 const std::vector<std::shared_ptr<IContextMenuItem>> pvrItems(CPVRContextMenuManager::GetInstance().GetMenuItems());
113 for (const auto &item : pvrItems)
114 m_items.emplace_back(item);
117 void CContextMenuManager::ReloadAddonItems()
119 VECADDONS addons;
120 m_addonMgr.GetAddons(addons, AddonType::CONTEXTMENU_ITEM);
122 std::vector<CContextMenuItem> addonItems;
123 for (const auto& addon : addons)
125 auto items = std::static_pointer_cast<CContextMenuAddon>(addon)->GetItems();
126 for (auto& item : items)
128 auto it = std::find(addonItems.begin(), addonItems.end(), item);
129 if (it == addonItems.end())
130 addonItems.push_back(item);
134 std::unique_lock<CCriticalSection> lock(m_criticalSection);
135 m_addonItems = std::move(addonItems);
137 CLog::Log(LOGDEBUG, "ContextMenuManager: addon menus reloaded.");
140 void CContextMenuManager::OnEvent(const ADDON::AddonEvent& event)
142 if (typeid(event) == typeid(AddonEvents::ReInstalled) ||
143 typeid(event) == typeid(AddonEvents::UnInstalled))
145 ReloadAddonItems();
147 else if (typeid(event) == typeid(AddonEvents::Enabled))
149 AddonPtr addon;
150 if (m_addonMgr.GetAddon(event.addonId, addon, AddonType::CONTEXTMENU_ITEM,
151 OnlyEnabled::CHOICE_YES))
153 std::unique_lock<CCriticalSection> lock(m_criticalSection);
154 auto items = std::static_pointer_cast<CContextMenuAddon>(addon)->GetItems();
155 for (auto& item : items)
157 auto it = std::find(m_addonItems.begin(), m_addonItems.end(), item);
158 if (it == m_addonItems.end())
159 m_addonItems.push_back(item);
161 CLog::Log(LOGDEBUG, "ContextMenuManager: loaded {}.", event.addonId);
164 else if (typeid(event) == typeid(AddonEvents::Disabled))
166 if (m_addonMgr.HasType(event.addonId, AddonType::CONTEXTMENU_ITEM))
168 ReloadAddonItems();
173 void CContextMenuManager::OnPVREvent(const PVRContextMenuEvent& event)
175 switch (event.action)
177 case PVRContextMenuEventAction::ADD_ITEM:
179 std::unique_lock<CCriticalSection> lock(m_criticalSection);
180 m_items.emplace_back(event.item);
181 break;
183 case PVRContextMenuEventAction::REMOVE_ITEM:
185 std::unique_lock<CCriticalSection> lock(m_criticalSection);
186 auto it = std::find(m_items.begin(), m_items.end(), event.item);
187 if (it != m_items.end())
188 m_items.erase(it);
189 break;
192 default:
193 break;
197 bool CContextMenuManager::IsVisible(
198 const CContextMenuItem& menuItem, const CContextMenuItem& root, const CFileItem& fileItem) const
200 if (menuItem.GetLabel(fileItem).empty() || !root.IsParentOf(menuItem))
201 return false;
203 if (menuItem.IsGroup())
205 std::unique_lock<CCriticalSection> lock(m_criticalSection);
206 return std::any_of(m_addonItems.begin(), m_addonItems.end(),
207 [&](const CContextMenuItem& other){ return menuItem.IsParentOf(other) && other.IsVisible(fileItem); });
210 return menuItem.IsVisible(fileItem);
213 bool CContextMenuManager::HasItems(const CFileItem& fileItem, const CContextMenuItem& root) const
215 //! @todo implement group support
216 if (&root == &CContextMenuManager::MAIN)
218 std::unique_lock<CCriticalSection> lock(m_criticalSection);
219 return std::any_of(m_items.cbegin(), m_items.cend(),
220 [&fileItem](const std::shared_ptr<const IContextMenuItem>& menu) {
221 return menu->IsVisible(fileItem);
224 return false;
227 ContextMenuView CContextMenuManager::GetItems(const CFileItem& fileItem,
228 const CContextMenuItem& root) const
230 ContextMenuView result;
231 //! @todo implement group support
232 if (&root == &CContextMenuManager::MAIN)
234 std::unique_lock<CCriticalSection> lock(m_criticalSection);
235 std::copy_if(m_items.begin(), m_items.end(), std::back_inserter(result),
236 [&](const std::shared_ptr<IContextMenuItem>& menu){ return menu->IsVisible(fileItem); });
238 return result;
241 bool CContextMenuManager::HasAddonItems(const CFileItem& fileItem,
242 const CContextMenuItem& root) const
244 std::unique_lock<CCriticalSection> lock(m_criticalSection);
245 return std::any_of(m_addonItems.cbegin(), m_addonItems.cend(),
246 [this, root, &fileItem](const CContextMenuItem& menu) {
247 return IsVisible(menu, root, fileItem);
251 ContextMenuView CContextMenuManager::GetAddonItems(const CFileItem& fileItem,
252 const CContextMenuItem& root) const
254 ContextMenuView result;
256 std::unique_lock<CCriticalSection> lock(m_criticalSection);
257 for (const auto& menu : m_addonItems)
258 if (IsVisible(menu, root, fileItem))
259 result.emplace_back(new CContextMenuItem(menu));
262 if (&root == &CContextMenuManager::MANAGE)
264 std::sort(result.begin(), result.end(),
265 [&](const ContextMenuView::value_type& lhs, const ContextMenuView::value_type& rhs)
267 return lhs->GetLabel(fileItem) < rhs->GetLabel(fileItem);
271 return result;
274 bool CONTEXTMENU::HasAnyMenuItemsFor(const std::shared_ptr<CFileItem>& fileItem,
275 const CContextMenuItem& root)
277 if (!fileItem)
278 return false;
280 if (fileItem->HasProperty("contextmenulabel(0)"))
281 return true;
283 const CContextMenuManager& contextMenuManager = CServiceBroker::GetContextMenuManager();
284 return (contextMenuManager.HasItems(*fileItem, root) ||
285 contextMenuManager.HasAddonItems(*fileItem, root));
288 bool CONTEXTMENU::ShowFor(const std::shared_ptr<CFileItem>& fileItem, const CContextMenuItem& root)
290 if (!fileItem)
291 return false;
293 const CContextMenuManager &contextMenuManager = CServiceBroker::GetContextMenuManager();
295 auto menuItems = contextMenuManager.GetItems(*fileItem, root);
296 for (auto&& item : contextMenuManager.GetAddonItems(*fileItem, root))
297 menuItems.emplace_back(std::move(item));
299 CContextButtons buttons;
300 // compute fileitem property-based contextmenu items
301 // unless we're browsing a child menu item
302 if (!root.HasParent())
304 int i = 0;
305 while (fileItem->HasProperty(StringUtils::Format("contextmenulabel({})", i)))
307 buttons.emplace_back(
308 ~buttons.size(),
309 fileItem->GetProperty(StringUtils::Format("contextmenulabel({})", i)).asString());
310 ++i;
313 const int propertyMenuSize = buttons.size();
315 if (menuItems.empty() && propertyMenuSize == 0)
316 return true;
318 buttons.reserve(menuItems.size());
319 for (size_t i = 0; i < menuItems.size(); ++i)
320 buttons.Add(i, menuItems[i]->GetLabel(*fileItem));
322 int selected = CGUIDialogContextMenu::Show(buttons);
323 if (selected < 0 || selected >= static_cast<int>(buttons.size()))
324 return false;
326 if (selected < propertyMenuSize)
328 CServiceBroker::GetAppMessenger()->SendMsg(
329 TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr,
330 fileItem->GetProperty(StringUtils::Format("contextmenuaction({})", selected)).asString());
331 return true;
334 return menuItems[selected - propertyMenuSize]->IsGroup()
335 ? ShowFor(fileItem, static_cast<const CContextMenuItem&>(
336 *menuItems[selected - propertyMenuSize]))
337 : menuItems[selected - propertyMenuSize]->Execute(fileItem);
340 bool CONTEXTMENU::LoopFrom(const IContextMenuItem& menu, const std::shared_ptr<CFileItem>& fileItem)
342 if (!fileItem)
343 return false;
344 if (menu.IsGroup())
345 return ShowFor(fileItem, static_cast<const CContextMenuItem&>(menu));
346 return menu.Execute(fileItem);