diff options
author | Kai Sommerfeld <kai.sommerfeld@gmx.com> | 2022-09-28 01:11:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-28 01:11:27 +0200 |
commit | f48d6c361fafc1b4487042147a82ee65933813da (patch) | |
tree | 2e40ac2bb375e4c6cad0e4ef81289633f8e33e12 | |
parent | bb3f4fe025a50c5ff28013b5f0c21fa9bccea40f (diff) | |
parent | 6366a7e455771ed465c549d2a14976b1c0afc726 (diff) |
Merge pull request #21928 from ksooo/pvr-refactor-guiactions
[PVR] Refactor CPVRGUIActions
55 files changed, 4671 insertions, 3638 deletions
diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp index a018f465a1..77cac5bb9b 100644 --- a/xbmc/FileItem.cpp +++ b/xbmc/FileItem.cpp @@ -39,7 +39,7 @@ #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/epg/EpgInfoTag.h" #include "pvr/epg/EpgSearchFilter.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" #include "pvr/recordings/PVRRecording.h" #include "pvr/timers/PVRTimerInfoTag.h" #include "settings/AdvancedSettings.h" @@ -175,7 +175,8 @@ CFileItem::CFileItem(const std::shared_ptr<PVR::CPVREpgInfoTag>& tag, std::shared_ptr<CPVRChannelGroupMember> groupMember = groupMemberIn; if (!groupMember) - groupMember = CServiceBroker::GetPVRManager().GUIActions()->GetChannelGroupMember(*this); + groupMember = + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(*this); if (!tag->IconPath().empty()) SetArt("icon", tag->IconPath()); @@ -3910,7 +3911,7 @@ CFileItem CFileItem::GetItemToPlay() const if (HasEPGInfoTag()) { const std::shared_ptr<CPVRChannelGroupMember> groupMember = - CServiceBroker::GetPVRManager().GUIActions()->GetChannelGroupMember(*this); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(*this); if (groupMember) return CFileItem(groupMember); } diff --git a/xbmc/application/Application.cpp b/xbmc/application/Application.cpp index b1f01d01b2..27b7bc80cb 100644 --- a/xbmc/application/Application.cpp +++ b/xbmc/application/Application.cpp @@ -9,12 +9,16 @@ #include "Application.h" #include "Autorun.h" +#include "CompileInfo.h" #include "GUIInfoManager.h" #include "HDRStatus.h" #include "LangInfo.h" #include "PlayListPlayer.h" #include "URL.h" #include "Util.h" +#include "addons/AddonInstaller.h" +#include "addons/AddonManager.h" +#include "addons/RepositoryUpdater.h" #include "addons/Skin.h" #include "addons/VFSEntry.h" #include "application/AppInboundProtocol.h" @@ -25,6 +29,7 @@ #include "cores/IPlayer.h" #include "cores/playercorefactory/PlayerCoreFactory.h" #include "dialogs/GUIDialogBusy.h" +#include "dialogs/GUIDialogCache.h" #include "dialogs/GUIDialogKaiToast.h" #include "events/EventLog.h" #include "events/NotificationEvent.h" @@ -36,6 +41,7 @@ #include "interfaces/builtins/Builtins.h" #include "interfaces/generic/ScriptInvocationManager.h" #include "music/MusicLibraryQueue.h" +#include "music/tags/MusicInfoTag.h" #include "network/EventServer.h" #include "network/Network.h" #include "platform/Environment.h" @@ -138,16 +144,8 @@ // PVR related include Files #include "pvr/PVRManager.h" -#include "pvr/guilib/PVRGUIActions.h" - -#include "dialogs/GUIDialogCache.h" -#include "utils/URIUtils.h" -#include "utils/XMLUtils.h" -#include "addons/AddonInstaller.h" -#include "addons/AddonManager.h" -#include "addons/RepositoryUpdater.h" -#include "music/tags/MusicInfoTag.h" -#include "CompileInfo.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" +#include "pvr/guilib/PVRGUIActionsPowerManagement.h" #ifdef TARGET_WINDOWS #include "win32util.h" @@ -165,12 +163,14 @@ #include <cdio/logging.h> #endif +#include "DatabaseManager.h" +#include "input/InputManager.h" #include "storage/MediaManager.h" -#include "utils/SaveFileStateJob.h" #include "utils/AlarmClock.h" +#include "utils/SaveFileStateJob.h" #include "utils/StringUtils.h" -#include "DatabaseManager.h" -#include "input/InputManager.h" +#include "utils/URIUtils.h" +#include "utils/XMLUtils.h" #ifdef TARGET_POSIX #include "platform/posix/XHandle.h" @@ -1055,7 +1055,7 @@ bool CApplication::OnAction(const CAction &action) if (action.GetID() == ACTION_BUILT_IN_FUNCTION) { if (!CBuiltins::GetInstance().IsSystemPowerdownCommand(action.GetName()) || - CServiceBroker::GetPVRManager().GUIActions()->CanSystemPowerdown()) + CServiceBroker::GetPVRManager().Get<PVR::GUI::PowerManagement>().CanSystemPowerdown()) { CBuiltins::GetInstance().Execute(action.GetName()); m_navigationTimer.StartZero(); @@ -1435,7 +1435,7 @@ void CApplication::OnApplicationMessage(ThreadMessage* pMsg) uint32_t msg = pMsg->dwMessage; if (msg == TMSG_SYSTEM_POWERDOWN) { - if (CServiceBroker::GetPVRManager().GUIActions()->CanSystemPowerdown()) + if (CServiceBroker::GetPVRManager().Get<PVR::GUI::PowerManagement>().CanSystemPowerdown()) msg = pMsg->param1; // perform requested shutdown action else return; // no shutdown @@ -2241,7 +2241,8 @@ bool CApplication::PlayMedia(CFileItem& item, const std::string& player, PLAYLIS } else if (item.IsPVR()) { - return CServiceBroker::GetPVRManager().GUIActions()->PlayMedia(CFileItemPtr(new CFileItem(item))); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayMedia( + CFileItemPtr(new CFileItem(item))); } CURL path(item.GetPath()); @@ -2909,7 +2910,7 @@ bool CApplication::ExecuteXBMCAction(std::string actionStr, const CGUIListItemPt if (CBuiltins::GetInstance().HasCommand(actionStr)) { if (!CBuiltins::GetInstance().IsSystemPowerdownCommand(actionStr) || - CServiceBroker::GetPVRManager().GUIActions()->CanSystemPowerdown()) + CServiceBroker::GetPVRManager().Get<PVR::GUI::PowerManagement>().CanSystemPowerdown()) CBuiltins::GetInstance().Execute(actionStr); } else diff --git a/xbmc/application/ApplicationPowerHandling.cpp b/xbmc/application/ApplicationPowerHandling.cpp index f84a8b6bdf..d2aed9bbcb 100644 --- a/xbmc/application/ApplicationPowerHandling.cpp +++ b/xbmc/application/ApplicationPowerHandling.cpp @@ -25,7 +25,8 @@ #include "powermanagement/PowerTypes.h" #include "profiles/ProfileManager.h" #include "pvr/PVRManager.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsPowerManagement.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "utils/AlarmClock.h" @@ -400,7 +401,7 @@ void CApplicationPowerHandling::ActivateScreenSaver(bool forceType /*= false */) else if (m_appPlayer.IsPlayingVideo() && settings->GetBool(CSettings::SETTING_SCREENSAVER_USEDIMONPAUSE)) bUseDim = true; - else if (CServiceBroker::GetPVRManager().GUIActions()->IsRunningChannelScan()) + else if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().IsRunningChannelScan()) bUseDim = true; if (bUseDim) @@ -518,7 +519,8 @@ void CApplicationPowerHandling::CheckShutdown() CVideoLibraryQueue::GetInstance().IsRunning() || CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive( WINDOW_DIALOG_PROGRESS) // progress dialog is onscreen - || !CServiceBroker::GetPVRManager().GUIActions()->CanSystemPowerdown(false)) + || + !CServiceBroker::GetPVRManager().Get<PVR::GUI::PowerManagement>().CanSystemPowerdown(false)) { m_shutdownTimer.StartZero(); return; diff --git a/xbmc/input/WindowTranslator.cpp b/xbmc/input/WindowTranslator.cpp index ac5714d5ac..fe2dd468a7 100644 --- a/xbmc/input/WindowTranslator.cpp +++ b/xbmc/input/WindowTranslator.cpp @@ -12,7 +12,7 @@ #include "application/Application.h" #include "guilib/WindowIDs.h" #include "pvr/PVRManager.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" #include "utils/StringUtils.h" #include "utils/log.h" @@ -294,11 +294,14 @@ int CWindowTranslator::GetVirtualWindow(int windowId) else if (g_application.CurrentFileItem().HasPVRChannelInfoTag()) { if (CServiceBroker::GetPVRManager() - .GUIActions() - ->GetChannelNumberInputHandler() + .Get<PVR::GUI::Channels>() + .GetChannelNumberInputHandler() .HasChannelNumber()) return WINDOW_FULLSCREEN_LIVETV_INPUT; - else if (CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().IsPreview()) + else if (CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNavigator() + .IsPreview()) return WINDOW_FULLSCREEN_LIVETV_PREVIEW; else return WINDOW_FULLSCREEN_LIVETV; @@ -313,11 +316,14 @@ int CWindowTranslator::GetVirtualWindow(int windowId) if (g_application.CurrentFileItem().HasPVRChannelInfoTag()) { if (CServiceBroker::GetPVRManager() - .GUIActions() - ->GetChannelNumberInputHandler() + .Get<PVR::GUI::Channels>() + .GetChannelNumberInputHandler() .HasChannelNumber()) return WINDOW_FULLSCREEN_RADIO_INPUT; - else if (CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().IsPreview()) + else if (CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNavigator() + .IsPreview()) return WINDOW_FULLSCREEN_RADIO_PREVIEW; else return WINDOW_FULLSCREEN_RADIO; diff --git a/xbmc/interfaces/builtins/PVRBuiltins.cpp b/xbmc/interfaces/builtins/PVRBuiltins.cpp index 26da63a6a8..7f2154ffa1 100644 --- a/xbmc/interfaces/builtins/PVRBuiltins.cpp +++ b/xbmc/interfaces/builtins/PVRBuiltins.cpp @@ -15,7 +15,7 @@ #include "guilib/GUIWindowManager.h" #include "guilib/guiinfo/GUIInfoLabels.h" #include "pvr/PVRManager.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsTimers.h" #include "pvr/windows/GUIWindowPVRGuide.h" #include "utils/log.h" @@ -39,7 +39,7 @@ static int SearchMissingIcons(const std::vector<std::string>& params) */ static int ToggleRecordPlayingChannel(const std::vector<std::string>& params) { - CServiceBroker::GetPVRManager().GUIActions()->ToggleRecordingOnPlayingChannel(); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().ToggleRecordingOnPlayingChannel(); return 0; } diff --git a/xbmc/interfaces/builtins/PlayerBuiltins.cpp b/xbmc/interfaces/builtins/PlayerBuiltins.cpp index 80ea8b0785..2b9891af47 100644 --- a/xbmc/interfaces/builtins/PlayerBuiltins.cpp +++ b/xbmc/interfaces/builtins/PlayerBuiltins.cpp @@ -21,7 +21,7 @@ #include "guilib/GUIWindowManager.h" #include "pvr/PVRManager.h" #include "pvr/channels/PVRChannel.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" #include "pvr/recordings/PVRRecording.h" #include "settings/MediaSettings.h" #include "settings/Settings.h" @@ -371,7 +371,7 @@ static int PlayerControl(const std::vector<std::string>& params) if (channel) { const std::shared_ptr<PVR::CPVRChannelGroupMember> groupMember = - CServiceBroker::GetPVRManager().GUIActions()->GetChannelGroupMember(channel); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(channel); if (!groupMember) { CLog::Log(LOGERROR, "ResumeLiveTv could not obtain channel group member for channel: {}", diff --git a/xbmc/interfaces/json-rpc/PVROperations.cpp b/xbmc/interfaces/json-rpc/PVROperations.cpp index 46ff382324..ce921b627e 100644 --- a/xbmc/interfaces/json-rpc/PVROperations.cpp +++ b/xbmc/interfaces/json-rpc/PVROperations.cpp @@ -19,7 +19,8 @@ #include "pvr/epg/Epg.h" #include "pvr/epg/EpgContainer.h" #include "pvr/epg/EpgInfoTag.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsTimers.h" #include "pvr/recordings/PVRRecordings.h" #include "pvr/timers/PVRTimerInfoTag.h" #include "pvr/timers/PVRTimers.h" @@ -144,7 +145,7 @@ JSONRPC_STATUS CPVROperations::GetChannelDetails(const std::string &method, ITra return InvalidParams; const std::shared_ptr<CPVRChannelGroupMember> groupMember = - CServiceBroker::GetPVRManager().GUIActions()->GetChannelGroupMember(channel); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(channel); if (!groupMember) return InvalidParams; @@ -278,7 +279,8 @@ JSONRPC_STATUS CPVROperations::Record(const std::string &method, ITransportLayer if (toggle) { - if (!CServiceBroker::GetPVRManager().GUIActions()->SetRecordingOnChannel(pChannel, !bIsRecording)) + if (!CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().SetRecordingOnChannel( + pChannel, !bIsRecording)) return FailedToExecute; } @@ -292,13 +294,13 @@ JSONRPC_STATUS CPVROperations::Scan(const std::string &method, ITransportLayer * if (parameterObject.isMember("clientid")) { - if (CServiceBroker::GetPVRManager().GUIActions()->StartChannelScan( + if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().StartChannelScan( parameterObject["clientid"].asInteger())) return ACK; } else { - if (CServiceBroker::GetPVRManager().GUIActions()->StartChannelScan()) + if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().StartChannelScan()) return ACK; } @@ -321,7 +323,7 @@ JSONRPC_STATUS CPVROperations::GetPropertyValue(const std::string &property, CVa else if (property == "scanning") { if (started) - result = CServiceBroker::GetPVRManager().GUIActions()->IsRunningChannelScan(); + result = CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().IsRunningChannelScan(); else result = false; } @@ -418,7 +420,7 @@ JSONRPC_STATUS CPVROperations::AddTimer(const std::string &method, ITransportLay parameterObject["reminder"].asBoolean(false)); if (newTimer) { - if (CServiceBroker::GetPVRManager().GUIActions()->AddTimer(newTimer)) + if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddTimer(newTimer)) return ACK; } return FailedToExecute; @@ -473,7 +475,7 @@ JSONRPC_STATUS CPVROperations::ToggleTimer(const std::string &method, ITransport if (!timer) return InvalidParams; - sentOkay = CServiceBroker::GetPVRManager().GUIActions()->AddTimer(timer); + sentOkay = CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddTimer(timer); } if (sentOkay) diff --git a/xbmc/interfaces/json-rpc/PlayerOperations.cpp b/xbmc/interfaces/json-rpc/PlayerOperations.cpp index bca574611b..986a6bd8e4 100644 --- a/xbmc/interfaces/json-rpc/PlayerOperations.cpp +++ b/xbmc/interfaces/json-rpc/PlayerOperations.cpp @@ -33,7 +33,8 @@ #include "pvr/channels/PVRChannelGroupMember.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/epg/EpgInfoTag.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" #include "pvr/recordings/PVRRecordings.h" #include "settings/DisplaySettings.h" #include "utils/Variant.h" @@ -731,7 +732,7 @@ JSONRPC_STATUS CPlayerOperations::Open(const std::string &method, ITransportLaye if (!epgTag || !epgTag->IsPlayable()) return InvalidParams; - if (!CServiceBroker::GetPVRManager().GUIActions()->PlayEpgTag( + if (!CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayEpgTag( std::make_shared<CFileItem>(epgTag))) return FailedToExecute; @@ -748,11 +749,11 @@ JSONRPC_STATUS CPlayerOperations::Open(const std::string &method, ITransportLaye return InvalidParams; const std::shared_ptr<CPVRChannelGroupMember> groupMember = - CServiceBroker::GetPVRManager().GUIActions()->GetChannelGroupMember(channel); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(channel); if (!groupMember) return InvalidParams; - if (!CServiceBroker::GetPVRManager().GUIActions()->PlayMedia( + if (!CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayMedia( std::make_shared<CFileItem>(groupMember))) return FailedToExecute; @@ -768,7 +769,8 @@ JSONRPC_STATUS CPlayerOperations::Open(const std::string &method, ITransportLaye if (!recording) return InvalidParams; - if (!CServiceBroker::GetPVRManager().GUIActions()->PlayMedia(std::make_shared<CFileItem>(recording))) + if (!CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayMedia( + std::make_shared<CFileItem>(recording))) return FailedToExecute; return ACK; diff --git a/xbmc/listproviders/DirectoryProvider.cpp b/xbmc/listproviders/DirectoryProvider.cpp index 6ee7f3ce51..6a9a9d5137 100644 --- a/xbmc/listproviders/DirectoryProvider.cpp +++ b/xbmc/listproviders/DirectoryProvider.cpp @@ -22,7 +22,7 @@ #include "pictures/PictureThumbLoader.h" #include "pvr/PVRManager.h" #include "pvr/PVRThumbLoader.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsUtils.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "utils/JobManager.h" @@ -440,7 +440,7 @@ bool CDirectoryProvider::OnInfo(const CGUIListItemPtr& item) } else if (fileItem->IsPVR()) { - return CServiceBroker::GetPVRManager().GUIActions()->OnInfo(fileItem); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Utils>().OnInfo(fileItem); } else if (fileItem->HasVideoInfoTag()) { diff --git a/xbmc/pvr/CMakeLists.txt b/xbmc/pvr/CMakeLists.txt index ed23157f97..e7a95a6515 100644 --- a/xbmc/pvr/CMakeLists.txt +++ b/xbmc/pvr/CMakeLists.txt @@ -1,6 +1,7 @@ set(SOURCES PVRCachedImage.cpp PVRCachedImages.cpp PVRChannelNumberInputHandler.cpp + PVRComponentRegistration.cpp PVRContextMenus.cpp PVRDatabase.cpp PVREdl.cpp @@ -11,9 +12,11 @@ set(SOURCES PVRCachedImage.cpp PVRStreamProperties.cpp PVRThumbLoader.cpp) -set(HEADERS PVRCachedImage.h +set(HEADERS IPVRComponent.h + PVRCachedImage.h PVRCachedImages.h PVRChannelNumberInputHandler.h + PVRComponentRegistration.h PVRContextMenus.h PVRDatabase.h PVREdl.h diff --git a/xbmc/pvr/IPVRComponent.h b/xbmc/pvr/IPVRComponent.h new file mode 100644 index 0000000000..8695095f18 --- /dev/null +++ b/xbmc/pvr/IPVRComponent.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2022 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +namespace PVR +{ +class IPVRComponent +{ +public: + virtual ~IPVRComponent() = default; +}; +} // namespace PVR diff --git a/xbmc/pvr/PVRComponentRegistration.cpp b/xbmc/pvr/PVRComponentRegistration.cpp new file mode 100644 index 0000000000..7532283710 --- /dev/null +++ b/xbmc/pvr/PVRComponentRegistration.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRComponentRegistration.h" + +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsClients.h" +#include "pvr/guilib/PVRGUIActionsDatabase.h" +#include "pvr/guilib/PVRGUIActionsEPG.h" +#include "pvr/guilib/PVRGUIActionsParentalControl.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" +#include "pvr/guilib/PVRGUIActionsPowerManagement.h" +#include "pvr/guilib/PVRGUIActionsRecordings.h" +#include "pvr/guilib/PVRGUIActionsTimers.h" +#include "pvr/guilib/PVRGUIActionsUtils.h" + +#include <memory> + +using namespace PVR; + +CPVRComponentRegistration::CPVRComponentRegistration() +{ + RegisterComponent(std::make_shared<CPVRGUIActionsChannels>()); + RegisterComponent(std::make_shared<CPVRGUIActionsClients>()); + RegisterComponent(std::make_shared<CPVRGUIActionsDatabase>()); + RegisterComponent(std::make_shared<CPVRGUIActionsEPG>()); + RegisterComponent(std::make_shared<CPVRGUIActionsParentalControl>()); + RegisterComponent(std::make_shared<CPVRGUIActionsPlayback>()); + RegisterComponent(std::make_shared<CPVRGUIActionsPowerManagement>()); + RegisterComponent(std::make_shared<CPVRGUIActionsRecordings>()); + RegisterComponent(std::make_shared<CPVRGUIActionsTimers>()); + RegisterComponent(std::make_shared<CPVRGUIActionsUtils>()); +} + +CPVRComponentRegistration::~CPVRComponentRegistration() +{ + DeregisterComponent(typeid(CPVRGUIActionsUtils)); + DeregisterComponent(typeid(CPVRGUIActionsTimers)); + DeregisterComponent(typeid(CPVRGUIActionsRecordings)); + DeregisterComponent(typeid(CPVRGUIActionsPowerManagement)); + DeregisterComponent(typeid(CPVRGUIActionsPlayback)); + DeregisterComponent(typeid(CPVRGUIActionsParentalControl)); + DeregisterComponent(typeid(CPVRGUIActionsEPG)); + DeregisterComponent(typeid(CPVRGUIActionsDatabase)); + DeregisterComponent(typeid(CPVRGUIActionsClients)); + DeregisterComponent(typeid(CPVRGUIActionsChannels)); +} diff --git a/xbmc/pvr/PVRComponentRegistration.h b/xbmc/pvr/PVRComponentRegistration.h new file mode 100644 index 0000000000..d81d449642 --- /dev/null +++ b/xbmc/pvr/PVRComponentRegistration.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "pvr/IPVRComponent.h" +#include "utils/ComponentContainer.h" + +namespace PVR +{ +class CPVRComponentRegistration : public CComponentContainer<IPVRComponent> +{ +public: + CPVRComponentRegistration(); + virtual ~CPVRComponentRegistration(); +}; +} // namespace PVR diff --git a/xbmc/pvr/PVRContextMenus.cpp b/xbmc/pvr/PVRContextMenus.cpp index f5e38f057b..7266baa841 100644 --- a/xbmc/pvr/PVRContextMenus.cpp +++ b/xbmc/pvr/PVRContextMenus.cpp @@ -18,7 +18,10 @@ #include "pvr/channels/PVRChannel.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/epg/EpgInfoTag.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsEPG.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" +#include "pvr/guilib/PVRGUIActionsRecordings.h" +#include "pvr/guilib/PVRGUIActionsTimers.h" #include "pvr/recordings/PVRRecording.h" #include "pvr/recordings/PVRRecordings.h" #include "pvr/recordings/PVRRecordingsPath.h" @@ -118,7 +121,7 @@ namespace PVR bool PlayEpgTag::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->PlayEpgTag(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayEpgTag(item); } /////////////////////////////////////////////////////////////////////////////// @@ -135,7 +138,8 @@ namespace PVR bool PlayRecording::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(item, true /* bCheckResume */); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording( + item, true /* bCheckResume */); } /////////////////////////////////////////////////////////////////////////////// @@ -171,9 +175,9 @@ namespace PVR bool ShowInformation::Execute(const CFileItemPtr& item) const { if (item->GetPVRRecordingInfoTag()) - return CServiceBroker::GetPVRManager().GUIActions()->ShowRecordingInfo(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().ShowRecordingInfo(item); - return CServiceBroker::GetPVRManager().GUIActions()->ShowEPGInfo(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo(item); } /////////////////////////////////////////////////////////////////////////////// @@ -190,7 +194,7 @@ namespace PVR bool ShowChannelGuide::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->ShowChannelEPG(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowChannelEPG(item); } /////////////////////////////////////////////////////////////////////////////// @@ -218,7 +222,7 @@ namespace PVR bool FindSimilar::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->FindSimilar(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().FindSimilar(item); } /////////////////////////////////////////////////////////////////////////////// @@ -268,10 +272,11 @@ namespace PVR channel = item->GetPVRChannelInfoTag(); if (channel) - return CServiceBroker::GetPVRManager().GUIActions()->SetRecordingOnChannel(channel, true); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().SetRecordingOnChannel( + channel, true); } - return CServiceBroker::GetPVRManager().GUIActions()->AddTimer(item, false); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddTimer(item, false); } /////////////////////////////////////////////////////////////////////////////// @@ -311,11 +316,11 @@ namespace PVR const std::shared_ptr<CPVRChannel> channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(epgTag); if (channel) - return CServiceBroker::GetPVRManager().GUIActions()->SetRecordingOnChannel(channel, - false); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().SetRecordingOnChannel( + channel, false); } - return CServiceBroker::GetPVRManager().GUIActions()->StopRecording(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().StopRecording(item); } /////////////////////////////////////////////////////////////////////////////// @@ -326,14 +331,14 @@ namespace PVR const std::shared_ptr<CPVRRecording> recording(item.GetPVRRecordingInfoTag()); if (recording && !recording->IsDeleted() && !recording->IsInProgress()) { - return CServiceBroker::GetPVRManager().GUIActions()->CanEditRecording(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().CanEditRecording(item); } return false; } bool EditRecording::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->EditRecording(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().EditRecording(item); } /////////////////////////////////////////////////////////////////////////////// @@ -371,7 +376,7 @@ namespace PVR bool DeleteRecording::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->DeleteRecording(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().DeleteRecording(item); } /////////////////////////////////////////////////////////////////////////////// @@ -388,7 +393,7 @@ namespace PVR bool UndeleteRecording::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->UndeleteRecording(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().UndeleteRecording(item); } /////////////////////////////////////////////////////////////////////////////// @@ -405,7 +410,8 @@ namespace PVR bool DeleteWatchedRecordings::Execute(const std::shared_ptr<CFileItem>& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->DeleteWatchedRecordings(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().DeleteWatchedRecordings( + item); } /////////////////////////////////////////////////////////////////////////////// @@ -424,7 +430,7 @@ namespace PVR bool AddReminder::Execute(const std::shared_ptr<CFileItem>& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->AddReminder(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddReminder(item); } /////////////////////////////////////////////////////////////////////////////// @@ -450,7 +456,7 @@ namespace PVR bool ToggleTimerState::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->ToggleTimerState(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().ToggleTimerState(item); } /////////////////////////////////////////////////////////////////////////////// @@ -465,7 +471,7 @@ namespace PVR bool AddTimerRule::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->AddTimerRule(item, true, true); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddTimerRule(item, true, true); } /////////////////////////////////////////////////////////////////////////////// @@ -498,7 +504,7 @@ namespace PVR bool EditTimerRule::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->EditTimerRule(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().EditTimerRule(item); } /////////////////////////////////////////////////////////////////////////////// @@ -519,9 +525,10 @@ namespace PVR bool DeleteTimerRule::Execute(const CFileItemPtr& item) const { - const std::shared_ptr<CFileItem> parentTimer = CServiceBroker::GetPVRManager().GUIActions()->GetTimerRule(item); + auto& timers = CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>(); + const std::shared_ptr<CFileItem> parentTimer = timers.GetTimerRule(item); if (parentTimer) - return CServiceBroker::GetPVRManager().GUIActions()->DeleteTimerRule(parentTimer); + return timers.DeleteTimerRule(parentTimer); return false; } @@ -558,7 +565,7 @@ namespace PVR bool EditTimer::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->EditTimer(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().EditTimer(item); } /////////////////////////////////////////////////////////////////////////////// @@ -590,7 +597,7 @@ namespace PVR bool DeleteTimer::Execute(const CFileItemPtr& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->DeleteTimer(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().DeleteTimer(item); } /////////////////////////////////////////////////////////////////////////////// @@ -653,7 +660,7 @@ namespace PVR bool ExecuteSearch::Execute(const std::shared_ptr<CFileItem>& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->ExecuteSavedSearch(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ExecuteSavedSearch(item); } /////////////////////////////////////////////////////////////////////////////// @@ -666,7 +673,7 @@ namespace PVR bool EditSearch::Execute(const std::shared_ptr<CFileItem>& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->EditSavedSearch(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().EditSavedSearch(item); } /////////////////////////////////////////////////////////////////////////////// @@ -679,7 +686,7 @@ namespace PVR bool RenameSearch::Execute(const std::shared_ptr<CFileItem>& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->RenameSavedSearch(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().RenameSavedSearch(item); } /////////////////////////////////////////////////////////////////////////////// @@ -692,7 +699,7 @@ namespace PVR bool DeleteSearch::Execute(const std::shared_ptr<CFileItem>& item) const { - return CServiceBroker::GetPVRManager().GUIActions()->DeleteSavedSearch(item); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().DeleteSavedSearch(item); } } // namespace CONEXTMENUITEM diff --git a/xbmc/pvr/PVRManager.cpp b/xbmc/pvr/PVRManager.cpp index 35ced6e03a..0b047f18ef 100644 --- a/xbmc/pvr/PVRManager.cpp +++ b/xbmc/pvr/PVRManager.cpp @@ -12,6 +12,7 @@ #include "guilib/LocalizeStrings.h" #include "interfaces/AnnouncementManager.h" #include "messaging/ApplicationMessenger.h" +#include "pvr/PVRComponentRegistration.h" #include "pvr/PVRDatabase.h" #include "pvr/PVRPlaybackState.h" #include "pvr/addons/PVRClient.h" @@ -22,7 +23,8 @@ #include "pvr/channels/PVRChannelGroups.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/epg/EpgInfoTag.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" #include "pvr/guilib/PVRGUIChannelIconUpdater.h" #include "pvr/guilib/PVRGUIProgressHandler.h" #include "pvr/guilib/guiinfo/PVRGUIInfo.h" @@ -195,7 +197,7 @@ CPVRManager::CPVRManager() m_timers(new CPVRTimers), m_addons(new CPVRClients), m_guiInfo(new CPVRGUIInfo), - m_guiActions(new CPVRGUIActions), + m_components(new CPVRComponentRegistration), m_epgContainer(m_events), m_pendingUpdates(new CPVRManagerJobQueue), m_database(new CPVRDatabase), @@ -307,12 +309,6 @@ std::shared_ptr<CPVRClient> CPVRManager::GetClient(int iClientId) const return m_addons->GetCreatedClient(iClientId); } -std::shared_ptr<CPVRGUIActions> CPVRManager::GUIActions() const -{ - // note: m_guiActions is const (only set/reset in ctor/dtor). no need for a lock here. - return m_guiActions; -} - std::shared_ptr<CPVRPlaybackState> CPVRManager::PlaybackState() const { // note: m_playbackState is const (only set/reset in ctor/dtor). no need for a lock here. @@ -775,7 +771,7 @@ void CPVRManager::TriggerPlayChannelOnStartup() if (IsStarted()) { CServiceBroker::GetJobManager()->Submit( - [this] { return GUIActions()->PlayChannelOnStartup(); }); + [this] { return Get<PVR::GUI::Playback>().PlayChannelOnStartup(); }); } } @@ -825,7 +821,7 @@ bool CPVRManager::IsCurrentlyParentalLocked(const std::shared_ptr<CPVRChannel>& void CPVRManager::OnPlaybackStarted(const CFileItemPtr& item) { m_playbackState->OnPlaybackStarted(item); - m_guiActions->OnPlaybackStarted(item); + Get<PVR::GUI::Channels>().OnPlaybackStarted(item); m_epgContainer.OnPlaybackStarted(); } @@ -835,7 +831,7 @@ void CPVRManager::OnPlaybackStopped(const CFileItemPtr& item) if (m_playbackState->OnPlaybackStopped(item)) PublishEvent(PVREvent::ChannelPlaybackStopped); - m_guiActions->OnPlaybackStopped(item); + Get<PVR::GUI::Channels>().OnPlaybackStopped(item); m_epgContainer.OnPlaybackStopped(); } diff --git a/xbmc/pvr/PVRManager.h b/xbmc/pvr/PVRManager.h index d23940e74f..423f3d5339 100644 --- a/xbmc/pvr/PVRManager.h +++ b/xbmc/pvr/PVRManager.h @@ -10,6 +10,7 @@ #include "addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr/pvr_general.h" #include "interfaces/IAnnouncer.h" +#include "pvr/PVRComponentRegistration.h" #include "pvr/epg/EpgContainer.h" #include "pvr/guilib/PVRGUIActionListener.h" #include "pvr/settings/PVRSettings.h" @@ -34,7 +35,6 @@ namespace PVR class CPVRClient; class CPVRClients; class CPVRDatabase; - class CPVRGUIActions; class CPVRGUIInfo; class CPVRGUIProgressHandler; class CPVRManagerJobQueue; @@ -108,6 +108,16 @@ namespace PVR const CVariant& data) override; /*! + * @brief Get a PVR component. + * @return The component. + */ + template<class T> + T& Get() + { + return *m_components->GetComponent<T>(); + } + + /*! * @brief Get the providers container. * @return The providers container. */ @@ -152,12 +162,6 @@ namespace PVR std::shared_ptr<CPVRClient> GetClient(int iClientId) const; /*! - * @brief Get access to the pvr gui actions. - * @return The gui actions. - */ - std::shared_ptr<CPVRGUIActions> GUIActions() const; - - /*! * @brief Get access to the pvr playback state. * @return The playback state. */ @@ -448,7 +452,7 @@ namespace PVR std::shared_ptr<CPVRTimers> m_timers; /*!< pointer to the timers container */ std::shared_ptr<CPVRClients> m_addons; /*!< pointer to the pvr addon container */ std::unique_ptr<CPVRGUIInfo> m_guiInfo; /*!< pointer to the guiinfo data */ - std::shared_ptr<CPVRGUIActions> m_guiActions; /*!< pointer to the pvr gui actions */ + std::shared_ptr<CPVRComponentRegistration> m_components; /*!< pointer to the PVR components */ CPVREpgContainer m_epgContainer; /*!< the epg container */ //@} diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp index cc392fa0ad..267b3c6345 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp @@ -34,7 +34,7 @@ #include "pvr/channels/PVRChannelGroups.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/dialogs/GUIDialogPVRGroupManager.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsParentalControl.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "storage/MediaManager.h" @@ -339,7 +339,8 @@ bool CGUIDialogPVRChannelManager::OnClickButtonRadioParentalLocked() bool selected(msg.GetParam1() == 1); // ask for PIN first - if (CServiceBroker::GetPVRManager().GUIActions()->CheckParentalPIN() != ParentalCheckResult::SUCCESS) + if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalPIN() != + ParentalCheckResult::SUCCESS) { // failed - reset to previous SET_CONTROL_SELECTED(GetID(), RADIOBUTTON_PARENTAL_LOCK, !selected); return false; diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp index 3ce4a05359..83a4628521 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp @@ -23,7 +23,9 @@ #include "pvr/channels/PVRChannelGroups.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/epg/EpgContainer.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" +#include "pvr/guilib/PVRGUIActionsUtils.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" @@ -88,7 +90,8 @@ void CGUIDialogPVRChannelsOSD::OnDeinitWindow(int nextWindowID) { if (m_group) { - CServiceBroker::GetPVRManager().GUIActions()->SetSelectedItemPath(m_group->IsRadio(), m_viewControl.GetSelectedItemPath()); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Utils>().SetSelectedItemPath( + m_group->IsRadio(), m_viewControl.GetSelectedItemPath()); // next OnInitWindow will set the group which is then selected m_group.reset(); @@ -105,7 +108,10 @@ bool CGUIDialogPVRChannelsOSD::OnAction(const CAction& action) case ACTION_MOUSE_LEFT_CLICK: { // If direct channel number input is active, select the entered channel. - if (CServiceBroker::GetPVRManager().GUIActions()->GetChannelNumberInputHandler().CheckInputAndExecuteAction()) + if (CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNumberInputHandler() + .CheckInputAndExecuteAction()) return true; if (m_viewControl.HasControl(GetFocusedControlID())) @@ -186,7 +192,8 @@ void CGUIDialogPVRChannelsOSD::Update() if (!m_group) { m_group = group; - m_viewControl.SetSelectedItem(pvrMgr.GUIActions()->GetSelectedItemPath(channel->IsRadio())); + m_viewControl.SetSelectedItem( + pvrMgr.Get<PVR::GUI::Utils>().GetSelectedItemPath(channel->IsRadio())); SaveSelectedItemPath(group->GroupID()); } } @@ -237,7 +244,8 @@ void CGUIDialogPVRChannelsOSD::GotoChannel(int item) if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRMENU_CLOSECHANNELOSDONSWITCH)) Close(); - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(itemptr, true /* bCheckResume */); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel( + itemptr, true /* bCheckResume */); } void CGUIDialogPVRChannelsOSD::Notify(const PVREvent& event) diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp index b2e1d9d3b7..7a1c5033b8 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp @@ -14,7 +14,9 @@ #include "pvr/PVRManager.h" #include "pvr/addons/PVRClient.h" #include "pvr/epg/EpgInfoTag.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsEPG.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" +#include "pvr/guilib/PVRGUIActionsTimers.h" #include "pvr/recordings/PVRRecordings.h" #include "pvr/timers/PVRTimerInfoTag.h" #include "pvr/timers/PVRTimers.h" @@ -63,14 +65,14 @@ bool CGUIDialogPVRGuideInfo::OnClickButtonRecord(const CGUIMessage& message) { const CFileItemPtr item(new CFileItem(timerTag)); if (timerTag->IsRecording()) - bReturn = CServiceBroker::GetPVRManager().GUIActions()->StopRecording(item); + bReturn = CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().StopRecording(item); else - bReturn = CServiceBroker::GetPVRManager().GUIActions()->DeleteTimer(item); + bReturn = CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().DeleteTimer(item); } else { const CFileItemPtr item(new CFileItem(m_progItem)); - bReturn = CServiceBroker::GetPVRManager().GUIActions()->AddTimer(item, false); + bReturn = CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddTimer(item, false); } } @@ -89,7 +91,8 @@ bool CGUIDialogPVRGuideInfo::OnClickButtonAddTimer(const CGUIMessage& message) if (m_progItem && !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(m_progItem)) { const CFileItemPtr item(new CFileItem(m_progItem)); - bReturn = CServiceBroker::GetPVRManager().GUIActions()->AddTimerRule(item, true, true); + bReturn = + CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddTimerRule(item, true, true); } } @@ -108,7 +111,7 @@ bool CGUIDialogPVRGuideInfo::OnClickButtonSetReminder(const CGUIMessage& message if (m_progItem && !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(m_progItem)) { const std::shared_ptr<CFileItem> item = std::make_shared<CFileItem>(m_progItem); - bReturn = CServiceBroker::GetPVRManager().GUIActions()->AddReminder(item); + bReturn = CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddReminder(item); } } @@ -130,11 +133,13 @@ bool CGUIDialogPVRGuideInfo::OnClickButtonPlay(const CGUIMessage& message) const CFileItemPtr item(new CFileItem(m_progItem)); if (message.GetSenderId() == CONTROL_BTN_PLAY_RECORDING) - CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(item, true /* bCheckResume */); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording( + item, true /* bCheckResume */); else if (message.GetSenderId() == CONTROL_BTN_PLAY_EPGTAG && m_progItem->IsPlayable()) - CServiceBroker::GetPVRManager().GUIActions()->PlayEpgTag(item); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayEpgTag(item); else - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(item, true /* bCheckResume */); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel( + item, true /* bCheckResume */); bReturn = true; } @@ -149,7 +154,8 @@ bool CGUIDialogPVRGuideInfo::OnClickButtonFind(const CGUIMessage& message) if (message.GetSenderId() == CONTROL_BTN_FIND) { Close(); - return CServiceBroker::GetPVRManager().GUIActions()->FindSimilar(std::make_shared<CFileItem>(m_progItem)); + return CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().FindSimilar( + std::make_shared<CFileItem>(m_progItem)); } return bReturn; diff --git a/xbmc/pvr/dialogs/GUIDialogPVRItemsViewBase.cpp b/xbmc/pvr/dialogs/GUIDialogPVRItemsViewBase.cpp index 636c15b4e3..be818e5839 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRItemsViewBase.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRItemsViewBase.cpp @@ -15,7 +15,7 @@ #include "input/actions/Action.h" #include "input/actions/ActionIDs.h" #include "pvr/PVRManager.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsEPG.h" #include "view/ViewState.h" #include <utility> @@ -95,7 +95,7 @@ void CGUIDialogPVRItemsViewBase::ShowInfo(int itemIdx) if (!item) return; - CServiceBroker::GetPVRManager().GUIActions()->ShowEPGInfo(item); + CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo(item); } bool CGUIDialogPVRItemsViewBase::ContextMenu(int itemIdx) diff --git a/xbmc/pvr/dialogs/GUIDialogPVRRecordingInfo.cpp b/xbmc/pvr/dialogs/GUIDialogPVRRecordingInfo.cpp index 1cf4655c0b..8879278259 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRRecordingInfo.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRRecordingInfo.cpp @@ -12,7 +12,8 @@ #include "ServiceBroker.h" #include "guilib/GUIMessage.h" #include "pvr/PVRManager.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsEPG.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" using namespace PVR; @@ -61,7 +62,8 @@ bool CGUIDialogPVRRecordingInfo::OnClickButtonPlay(const CGUIMessage& message) Close(); if (m_recordItem) - CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(m_recordItem, true /* check resume */); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording( + m_recordItem, true /* check resume */); bReturn = true; } @@ -78,7 +80,7 @@ bool CGUIDialogPVRRecordingInfo::OnClickButtonFind(const CGUIMessage& message) Close(); if (m_recordItem) - CServiceBroker::GetPVRManager().GUIActions()->FindSimilar(m_recordItem); + CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().FindSimilar(m_recordItem); bReturn = true; } diff --git a/xbmc/pvr/guilib/CMakeLists.txt b/xbmc/pvr/guilib/CMakeLists.txt index 80e27d38b4..3a73a68be5 100644 --- a/xbmc/pvr/guilib/CMakeLists.txt +++ b/xbmc/pvr/guilib/CMakeLists.txt @@ -1,7 +1,16 @@ set(SOURCES GUIEPGGridContainer.cpp GUIEPGGridContainerModel.cpp PVRGUIActionListener.cpp - PVRGUIActions.cpp + PVRGUIActionsChannels.cpp + PVRGUIActionsClients.cpp + PVRGUIActionsDatabase.cpp + PVRGUIActionsEPG.cpp + PVRGUIActionsUtils.cpp + PVRGUIActionsParentalControl.cpp + PVRGUIActionsPlayback.cpp + PVRGUIActionsPowerManagement.cpp + PVRGUIActionsRecordings.cpp + PVRGUIActionsTimers.cpp PVRGUIChannelIconUpdater.cpp PVRGUIChannelNavigator.cpp PVRGUIProgressHandler.cpp) @@ -9,7 +18,16 @@ set(SOURCES GUIEPGGridContainer.cpp set(HEADERS GUIEPGGridContainer.h GUIEPGGridContainerModel.h PVRGUIActionListener.h - PVRGUIActions.h + PVRGUIActionsChannels.h + PVRGUIActionsClients.h + PVRGUIActionsDatabase.h + PVRGUIActionsEPG.h + PVRGUIActionsUtils.h + PVRGUIActionsParentalControl.h + PVRGUIActionsPlayback.h + PVRGUIActionsPowerManagement.h + PVRGUIActionsRecordings.h + PVRGUIActionsTimers.h PVRGUIChannelIconUpdater.h PVRGUIChannelNavigator.h PVRGUIProgressHandler.h) diff --git a/xbmc/pvr/guilib/PVRGUIActionListener.cpp b/xbmc/pvr/guilib/PVRGUIActionListener.cpp index 38dfbddc63..464cbfa727 100644 --- a/xbmc/pvr/guilib/PVRGUIActionListener.cpp +++ b/xbmc/pvr/guilib/PVRGUIActionListener.cpp @@ -26,7 +26,11 @@ #include "pvr/channels/PVRChannelGroup.h" #include "pvr/channels/PVRChannelGroups.h" #include "pvr/channels/PVRChannelGroupsContainer.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsClients.h" +#include "pvr/guilib/PVRGUIActionsDatabase.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" +#include "pvr/guilib/PVRGUIActionsTimers.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "settings/lib/Setting.h" @@ -111,15 +115,18 @@ bool CPVRGUIActionListener::OnAction(const CAction& action) { case ACTION_PVR_PLAY: if (!bIsPlayingPVR) - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(PlaybackTypeAny); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel( + PlaybackTypeAny); break; case ACTION_PVR_PLAY_TV: if (!bIsPlayingPVR || g_application.CurrentFileItem().GetPVRChannelInfoTag()->IsRadio()) - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(PlaybackTypeTV); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel( + PlaybackTypeTV); break; case ACTION_PVR_PLAY_RADIO: if (!bIsPlayingPVR || !g_application.CurrentFileItem().GetPVRChannelInfoTag()->IsRadio()) - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(PlaybackTypeRadio); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel( + PlaybackTypeRadio); break; } return true; @@ -168,7 +175,10 @@ bool CPVRGUIActionListener::OnAction(const CAction& action) int iRemote = bIsJumpSMS ? action.GetID() - (ACTION_JUMP_SMS2 - REMOTE_2) : action.GetID(); cCharacter = static_cast<char>(iRemote - REMOTE_0) + '0'; } - CServiceBroker::GetPVRManager().GUIActions()->GetChannelNumberInputHandler().AppendChannelNumberCharacter(cCharacter); + CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNumberInputHandler() + .AppendChannelNumberCharacter(cCharacter); return true; } return false; @@ -179,7 +189,7 @@ bool CPVRGUIActionListener::OnAction(const CAction& action) if (!bIsPlayingPVR) return false; - CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().ToggleInfo(); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelNavigator().ToggleInfo(); return true; } @@ -189,15 +199,25 @@ bool CPVRGUIActionListener::OnAction(const CAction& action) return false; // If the button that caused this action matches action "Select" ... - if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRPLAYBACK_CONFIRMCHANNELSWITCH) && - CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().IsPreview()) + if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_PVRPLAYBACK_CONFIRMCHANNELSWITCH) && + CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNavigator() + .IsPreview()) { // ... and if "confirm channel switch" setting is active and a channel // preview is currently shown, switch to the currently previewed channel. - CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().SwitchToCurrentChannel(); + CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNavigator() + .SwitchToCurrentChannel(); return true; } - else if (CServiceBroker::GetPVRManager().GUIActions()->GetChannelNumberInputHandler().CheckInputAndExecuteAction()) + else if (CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNumberInputHandler() + .CheckInputAndExecuteAction()) { // ... or if the action was processed by direct channel number input, we're done. return true; @@ -210,7 +230,7 @@ bool CPVRGUIActionListener::OnAction(const CAction& action) if (!bIsPlayingPVR) return false; - CServiceBroker::GetPVRManager().GUIActions()->SeekForward(); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SeekForward(); return true; } @@ -219,7 +239,8 @@ bool CPVRGUIActionListener::OnAction(const CAction& action) if (!bIsPlayingPVR) return false; - CServiceBroker::GetPVRManager().GUIActions()->SeekBackward(CApplication::ACTION_PREV_ITEM_THRESHOLD); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SeekBackward( + CApplication::ACTION_PREV_ITEM_THRESHOLD); return true; } @@ -229,7 +250,10 @@ bool CPVRGUIActionListener::OnAction(const CAction& action) if (!bIsPlayingPVR) return false; - CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().SelectNextChannel(GetChannelSwitchMode(action.GetID())); + CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNavigator() + .SelectNextChannel(GetChannelSwitchMode(action.GetID())); return true; } @@ -239,7 +263,10 @@ bool CPVRGUIActionListener::OnAction(const CAction& action) if (!bIsPlayingPVR) return false; - CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().SelectPreviousChannel(GetChannelSwitchMode(action.GetID())); + CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNavigator() + .SelectPreviousChannel(GetChannelSwitchMode(action.GetID())); return true; } @@ -261,20 +288,20 @@ bool CPVRGUIActionListener::OnAction(const CAction& action) if (!groupMember) return false; - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel( + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel( std::make_shared<CFileItem>(groupMember), false); return true; } case ACTION_RECORD: { - CServiceBroker::GetPVRManager().GUIActions()->ToggleRecordingOnPlayingChannel(); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().ToggleRecordingOnPlayingChannel(); return true; } case ACTION_PVR_ANNOUNCE_REMINDERS: { - CServiceBroker::GetPVRManager().GUIActions()->AnnounceReminders(); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AnnounceReminders(); return true; } } @@ -320,11 +347,11 @@ void CPVRGUIActionListener::OnSettingAction(const std::shared_ptr<const CSetting const std::string& settingId = setting->GetId(); if (settingId == CSettings::SETTING_PVRMANAGER_RESETDB) { - CServiceBroker::GetPVRManager().GUIActions()->ResetPVRDatabase(false); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Database>().ResetDatabase(false); } else if (settingId == CSettings::SETTING_EPG_RESETEPG) { - CServiceBroker::GetPVRManager().GUIActions()->ResetPVRDatabase(true); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Database>().ResetDatabase(true); } else if (settingId == CSettings::SETTING_PVRMANAGER_CLIENTPRIORITIES) { @@ -358,7 +385,7 @@ void CPVRGUIActionListener::OnSettingAction(const std::shared_ptr<const CSetting } else if (settingId == CSettings::SETTING_PVRMANAGER_CHANNELSCAN) { - CServiceBroker::GetPVRManager().GUIActions()->StartChannelScan(); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().StartChannelScan(); } else if (settingId == CSettings::SETTING_PVRMENU_SEARCHICONS) { @@ -366,7 +393,7 @@ void CPVRGUIActionListener::OnSettingAction(const std::shared_ptr<const CSetting } else if (settingId == CSettings::SETTING_PVRCLIENT_MENUHOOK) { - CServiceBroker::GetPVRManager().GUIActions()->ProcessSettingsMenuHooks(); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Clients>().ProcessSettingsMenuHooks(); } else if (settingId == CSettings::SETTING_PVRMANAGER_ADDONS) { diff --git a/xbmc/pvr/guilib/PVRGUIActions.cpp b/xbmc/pvr/guilib/PVRGUIActions.cpp deleted file mode 100644 index 52e3741d78..0000000000 --- a/xbmc/pvr/guilib/PVRGUIActions.cpp +++ /dev/null @@ -1,2835 +0,0 @@ -/* - * Copyright (C) 2016-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#include "PVRGUIActions.h" - -#include "FileItem.h" -#include "ServiceBroker.h" -#include "Util.h" -#include "application/ApplicationEnums.h" -#include "cores/DataCacheCore.h" -#include "dialogs/GUIDialogBusy.h" -#include "dialogs/GUIDialogKaiToast.h" -#include "dialogs/GUIDialogNumeric.h" -#include "dialogs/GUIDialogProgress.h" -#include "dialogs/GUIDialogSelect.h" -#include "dialogs/GUIDialogYesNo.h" -#include "filesystem/IDirectory.h" -#include "guilib/GUIComponent.h" -#include "guilib/GUIKeyboardFactory.h" -#include "guilib/GUIWindowManager.h" -#include "guilib/LocalizeStrings.h" -#include "guilib/WindowIDs.h" -#include "input/actions/Action.h" -#include "input/actions/ActionIDs.h" -#include "messaging/ApplicationMessenger.h" -#include "messaging/helpers/DialogHelper.h" -#include "messaging/helpers/DialogOKHelper.h" -#include "network/Network.h" -#include "pvr/PVRDatabase.h" -#include "pvr/PVREventLogJob.h" -#include "pvr/PVRItem.h" -#include "pvr/PVRManager.h" -#include "pvr/PVRPlaybackState.h" -#include "pvr/PVRStreamProperties.h" -#include "pvr/addons/PVRClient.h" -#include "pvr/addons/PVRClientMenuHooks.h" -#include "pvr/addons/PVRClients.h" -#include "pvr/channels/PVRChannel.h" -#include "pvr/channels/PVRChannelGroup.h" -#include "pvr/channels/PVRChannelGroupMember.h" -#include "pvr/channels/PVRChannelGroups.h" -#include "pvr/channels/PVRChannelGroupsContainer.h" -#include "pvr/dialogs/GUIDialogPVRChannelGuide.h" -#include "pvr/dialogs/GUIDialogPVRGuideInfo.h" -#include "pvr/dialogs/GUIDialogPVRRecordingInfo.h" -#include "pvr/dialogs/GUIDialogPVRRecordingSettings.h" -#include "pvr/dialogs/GUIDialogPVRTimerSettings.h" -#include "pvr/epg/EpgContainer.h" -#include "pvr/epg/EpgDatabase.h" -#include "pvr/epg/EpgInfoTag.h" -#include "pvr/epg/EpgSearchFilter.h" -#include "pvr/recordings/PVRRecording.h" -#include "pvr/recordings/PVRRecordings.h" -#include "pvr/recordings/PVRRecordingsPath.h" -#include "pvr/timers/PVRTimerInfoTag.h" -#include "pvr/timers/PVRTimers.h" -#include "pvr/windows/GUIWindowPVRSearch.h" -#include "settings/MediaSettings.h" -#include "settings/Settings.h" -#include "threads/IRunnable.h" -#include "utils/StringUtils.h" -#include "utils/SystemInfo.h" -#include "utils/URIUtils.h" -#include "utils/Variant.h" -#include "utils/log.h" -#include "video/VideoDatabase.h" - -#include <chrono> -#include <iterator> -#include <map> -#include <memory> -#include <mutex> -#include <numeric> -#include <string> -#include <thread> -#include <utility> -#include <vector> - -using namespace KODI::MESSAGING; - -namespace -{ -PVR::CGUIWindowPVRSearchBase* GetSearchWindow(bool bRadio) -{ - const int windowSearchId = bRadio ? WINDOW_RADIO_SEARCH : WINDOW_TV_SEARCH; - - PVR::CGUIWindowPVRSearchBase* windowSearch; - - CGUIWindowManager& windowMgr = CServiceBroker::GetGUI()->GetWindowManager(); - if (bRadio) - windowSearch = windowMgr.GetWindow<PVR::CGUIWindowPVRRadioSearch>(windowSearchId); - else - windowSearch = windowMgr.GetWindow<PVR::CGUIWindowPVRTVSearch>(windowSearchId); - - if (!windowSearch) - CLog::LogF(LOGERROR, "Unable to get {}!", bRadio ? "WINDOW_RADIO_SEARCH" : "WINDOW_TV_SEARCH"); - - return windowSearch; -} -} // unnamed namespace - -namespace PVR -{ - class AsyncRecordingAction : private IRunnable - { - public: - bool Execute(const CFileItemPtr& item); - - protected: - AsyncRecordingAction() = default; - - private: - // IRunnable implementation - void Run() override; - - // the worker function - virtual bool DoRun(const CFileItemPtr& item) = 0; - - CFileItemPtr m_item; - bool m_bSuccess = false; - }; - - bool AsyncRecordingAction::Execute(const CFileItemPtr& item) - { - m_item = item; - CGUIDialogBusy::Wait(this, 100, false); - return m_bSuccess; - } - - void AsyncRecordingAction::Run() - { - m_bSuccess = DoRun(m_item); - - if (m_bSuccess) - CServiceBroker::GetPVRManager().TriggerRecordingsUpdate(); - } - - class AsyncRenameRecording : public AsyncRecordingAction - { - public: - explicit AsyncRenameRecording(const std::string& strNewName) : m_strNewName(strNewName) {} - - private: - bool DoRun(const std::shared_ptr<CFileItem>& item) override - { - if (item->IsUsablePVRRecording()) - { - return item->GetPVRRecordingInfoTag()->Rename(m_strNewName); - } - else - { - CLog::LogF(LOGERROR, "Cannot rename item '{}': no valid recording tag", item->GetPath()); - return false; - } - } - std::string m_strNewName; - }; - - class AsyncDeleteRecording : public AsyncRecordingAction - { - public: - explicit AsyncDeleteRecording(bool bWatchedOnly = false) : m_bWatchedOnly(bWatchedOnly) {} - - private: - bool DoRun(const std::shared_ptr<CFileItem>& item) override - { - CFileItemList items; - if (item->m_bIsFolder) - { - CUtil::GetRecursiveListing(item->GetPath(), items, "", XFILE::DIR_FLAG_NO_FILE_INFO); - } - else - { - items.Add(item); - } - - return std::accumulate( - items.cbegin(), items.cend(), true, [this](bool success, const auto& itemToDelete) { - return (itemToDelete->IsPVRRecording() && - (!m_bWatchedOnly || - itemToDelete->GetPVRRecordingInfoTag()->GetPlayCount() > 0) && - !itemToDelete->GetPVRRecordingInfoTag()->Delete()) - ? false - : success; - }); - } - bool m_bWatchedOnly = false; - }; - - class AsyncEmptyRecordingsTrash : public AsyncRecordingAction - { - private: - bool DoRun(const std::shared_ptr<CFileItem>& item) override - { - return CServiceBroker::GetPVRManager().Clients()->DeleteAllRecordingsFromTrash() == PVR_ERROR_NO_ERROR; - } - }; - - class AsyncUndeleteRecording : public AsyncRecordingAction - { - private: - bool DoRun(const std::shared_ptr<CFileItem>& item) override - { - if (item->IsDeletedPVRRecording()) - { - return item->GetPVRRecordingInfoTag()->Undelete(); - } - else - { - CLog::LogF(LOGERROR, "Cannot undelete item '{}': no valid recording tag", item->GetPath()); - return false; - } - } - }; - - class AsyncSetRecordingPlayCount : public AsyncRecordingAction - { - private: - bool DoRun(const CFileItemPtr& item) override - { - const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*item); - if (client) - { - const std::shared_ptr<CPVRRecording> recording = item->GetPVRRecordingInfoTag(); - return client->SetRecordingPlayCount(*recording, recording->GetLocalPlayCount()) == PVR_ERROR_NO_ERROR; - } - return false; - } - }; - - class AsyncSetRecordingLifetime : public AsyncRecordingAction - { - private: - bool DoRun(const CFileItemPtr& item) override - { - const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*item); - if (client) - return client->SetRecordingLifetime(*item->GetPVRRecordingInfoTag()) == PVR_ERROR_NO_ERROR; - return false; - } - }; - - CPVRGUIActions::CPVRGUIActions() - : m_settings({CSettings::SETTING_LOOKANDFEEL_STARTUPACTION, - CSettings::SETTING_PVRMANAGER_PRESELECTPLAYINGCHANNEL, - CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME, - CSettings::SETTING_PVRRECORD_INSTANTRECORDACTION, - CSettings::SETTING_PVRPLAYBACK_CONFIRMCHANNELSWITCH, - CSettings::SETTING_PVRPLAYBACK_SWITCHTOFULLSCREENCHANNELTYPES, - CSettings::SETTING_PVRPARENTAL_PIN, CSettings::SETTING_PVRPARENTAL_ENABLED, - CSettings::SETTING_PVRPOWERMANAGEMENT_DAILYWAKEUPTIME, - CSettings::SETTING_PVRPOWERMANAGEMENT_BACKENDIDLETIME, - CSettings::SETTING_PVRREMINDERS_AUTOCLOSEDELAY, - CSettings::SETTING_PVRREMINDERS_AUTORECORD, - CSettings::SETTING_PVRREMINDERS_AUTOSWITCH}) - { - } - - bool CPVRGUIActions::ShowEPGInfo(const CFileItemPtr& item) const - { - const std::shared_ptr<CPVRChannel> channel(CPVRItem(item).GetChannel()); - if (channel && CheckParentalLock(channel) != ParentalCheckResult::SUCCESS) - return false; - - const std::shared_ptr<CPVREpgInfoTag> epgTag(CPVRItem(item).GetEpgInfoTag()); - if (!epgTag) - { - CLog::LogF(LOGERROR, "No epg tag!"); - return false; - } - - CGUIDialogPVRGuideInfo* pDlgInfo = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRGuideInfo>(WINDOW_DIALOG_PVR_GUIDE_INFO); - if (!pDlgInfo) - { - CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PVR_GUIDE_INFO!"); - return false; - } - - pDlgInfo->SetProgInfo(epgTag); - pDlgInfo->Open(); - return true; - } - - - bool CPVRGUIActions::ShowChannelEPG(const CFileItemPtr& item) const - { - const std::shared_ptr<CPVRChannel> channel(CPVRItem(item).GetChannel()); - if (channel && CheckParentalLock(channel) != ParentalCheckResult::SUCCESS) - return false; - - CGUIDialogPVRChannelGuide* pDlgInfo = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRChannelGuide>(WINDOW_DIALOG_PVR_CHANNEL_GUIDE); - if (!pDlgInfo) - { - CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PVR_CHANNEL_GUIDE!"); - return false; - } - - pDlgInfo->Open(channel); - return true; - } - - - bool CPVRGUIActions::ShowRecordingInfo(const CFileItemPtr& item) const - { - if (!item->IsPVRRecording()) - { - CLog::LogF(LOGERROR, "No recording!"); - return false; - } - - CGUIDialogPVRRecordingInfo* pDlgInfo = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRRecordingInfo>(WINDOW_DIALOG_PVR_RECORDING_INFO); - if (!pDlgInfo) - { - CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PVR_RECORDING_INFO!"); - return false; - } - - pDlgInfo->SetRecording(item.get()); - pDlgInfo->Open(); - return true; - } - - bool CPVRGUIActions::FindSimilar(const std::shared_ptr<CFileItem>& item) const - { - CGUIWindowPVRSearchBase* windowSearch = GetSearchWindow(CPVRItem(item).IsRadio()); - if (!windowSearch) - return false; - - //! @todo If we want dialogs to spawn program search in a clean way - without having to force-close any - // other dialogs - we must introduce a search dialog with functionality similar to the search window. - - for (int iId = CServiceBroker::GetGUI()->GetWindowManager().GetTopmostModalDialog(true /* ignoreClosing */); - iId != WINDOW_INVALID; - iId = CServiceBroker::GetGUI()->GetWindowManager().GetTopmostModalDialog(true /* ignoreClosing */)) - { - CLog::LogF(LOGWARNING, - "Have to close modal dialog with id {} before search window can be opened.", iId); - - CGUIWindow* window = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(iId); - if (window) - { - window->Close(); - } - else - { - CLog::LogF(LOGERROR, "Unable to get window instance {}! Cannot open search window.", iId); - return false; // return, otherwise we run into an endless loop - } - } - - windowSearch->SetItemToSearch(item); - CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(windowSearch->GetID()); - return true; - }; - - bool CPVRGUIActions::ShowTimerSettings(const std::shared_ptr<CPVRTimerInfoTag>& timer) const - { - CGUIDialogPVRTimerSettings* pDlgInfo = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRTimerSettings>(WINDOW_DIALOG_PVR_TIMER_SETTING); - if (!pDlgInfo) - { - CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PVR_TIMER_SETTING!"); - return false; - } - - pDlgInfo->SetTimer(timer); - pDlgInfo->Open(); - - return pDlgInfo->IsConfirmed(); - } - - bool CPVRGUIActions::AddReminder(const std::shared_ptr<CFileItem>& item) const - { - const std::shared_ptr<CPVREpgInfoTag> epgTag = CPVRItem(item).GetEpgInfoTag(); - if (!epgTag) - { - CLog::LogF(LOGERROR, "No epg tag!"); - return false; - } - - if (CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epgTag)) - { - HELPERS::ShowOKDialogText(CVariant{19033}, // "Information" - CVariant{19034}); // "There is already a timer set for this event" - return false; - } - - const std::shared_ptr<CPVRTimerInfoTag> newTimer = CPVRTimerInfoTag::CreateReminderFromEpg(epgTag); - if (!newTimer) - { - HELPERS::ShowOKDialogText(CVariant{19033}, // "Information" - CVariant{19094}); // Timer creation failed. Unsupported timer type. - return false; - } - - return AddTimer(newTimer); - } - - bool CPVRGUIActions::AddTimer(bool bRadio) const - { - const std::shared_ptr<CPVRTimerInfoTag> newTimer(new CPVRTimerInfoTag(bRadio)); - if (ShowTimerSettings(newTimer)) - { - return AddTimer(newTimer); - } - return false; - } - - bool CPVRGUIActions::AddTimer(const CFileItemPtr& item, bool bShowTimerSettings) const - { - return AddTimer(item, false, bShowTimerSettings, false); - } - - bool CPVRGUIActions::AddTimerRule(const std::shared_ptr<CFileItem>& item, bool bShowTimerSettings, bool bFallbackToOneShotTimer) const - { - return AddTimer(item, true, bShowTimerSettings, bFallbackToOneShotTimer); - } - - bool CPVRGUIActions::AddTimer(const std::shared_ptr<CFileItem>& item, bool bCreateRule, bool bShowTimerSettings, bool bFallbackToOneShotTimer) const - { - const std::shared_ptr<CPVRChannel> channel(CPVRItem(item).GetChannel()); - if (!channel) - { - CLog::LogF(LOGERROR, "No channel!"); - return false; - } - - if (CheckParentalLock(channel) != ParentalCheckResult::SUCCESS) - return false; - - std::shared_ptr<CPVREpgInfoTag> epgTag = CPVRItem(item).GetEpgInfoTag(); - if (epgTag) - { - if (epgTag->IsGapTag()) - epgTag.reset(); // for gap tags, we can only create instant timers - } - else if (bCreateRule) - { - CLog::LogF(LOGERROR, "No epg tag!"); - return false; - } - - std::shared_ptr<CPVRTimerInfoTag> timer(bCreateRule || !epgTag ? nullptr : CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epgTag)); - std::shared_ptr<CPVRTimerInfoTag> rule (bCreateRule ? CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer) : nullptr); - if (timer || rule) - { - HELPERS::ShowOKDialogText(CVariant{19033}, CVariant{19034}); // "Information", "There is already a timer set for this event" - return false; - } - - std::shared_ptr<CPVRTimerInfoTag> newTimer(epgTag ? CPVRTimerInfoTag::CreateFromEpg(epgTag, bCreateRule) : CPVRTimerInfoTag::CreateInstantTimerTag(channel)); - if (!newTimer) - { - if (bCreateRule && bFallbackToOneShotTimer) - newTimer = CPVRTimerInfoTag::CreateFromEpg(epgTag, false); - - if (!newTimer) - { - HELPERS::ShowOKDialogText(CVariant{19033}, // "Information" - bCreateRule - ? CVariant{19095} // Timer rule creation failed. Unsupported timer type. - : CVariant{19094}); // Timer creation failed. Unsupported timer type. - return false; - } - } - - if (bShowTimerSettings) - { - if (!ShowTimerSettings(newTimer)) - return false; - } - - return AddTimer(newTimer); - } - - bool CPVRGUIActions::AddTimer(const std::shared_ptr<CPVRTimerInfoTag>& item) const - { - if (!item->Channel() && !item->GetTimerType()->IsEpgBasedTimerRule()) - { - CLog::LogF(LOGERROR, "No channel given"); - HELPERS::ShowOKDialogText(CVariant{257}, CVariant{19109}); // "Error", "Could not save the timer. Check the log for more information about this message." - return false; - } - - if (!item->IsTimerRule() && item->GetEpgInfoTag() && !item->GetEpgInfoTag()->IsRecordable()) - { - HELPERS::ShowOKDialogText(CVariant{19033}, CVariant{19189}); // "Information", "The PVR backend does not allow to record this event." - return false; - } - - if (CheckParentalLock(item->Channel()) != ParentalCheckResult::SUCCESS) - return false; - - if (!CServiceBroker::GetPVRManager().Timers()->AddTimer(item)) - { - HELPERS::ShowOKDialogText(CVariant{257}, CVariant{19109}); // "Error", "Could not save the timer. Check the log for more information about this message." - return false; - } - - return true; - } - - namespace - { - enum PVRRECORD_INSTANTRECORDACTION - { - NONE = -1, - RECORD_CURRENT_SHOW = 0, - RECORD_INSTANTRECORDTIME = 1, - ASK = 2, - RECORD_30_MINUTES = 3, - RECORD_60_MINUTES = 4, - RECORD_120_MINUTES = 5, - RECORD_NEXT_SHOW = 6 - }; - - class InstantRecordingActionSelector - { - public: - explicit InstantRecordingActionSelector(int iInstantRecordTime); - virtual ~InstantRecordingActionSelector() = default; - - void AddAction(PVRRECORD_INSTANTRECORDACTION eAction, const std::string& title); - void PreSelectAction(PVRRECORD_INSTANTRECORDACTION eAction); - PVRRECORD_INSTANTRECORDACTION Select(); - - private: - int m_iInstantRecordTime; - CGUIDialogSelect* m_pDlgSelect; // not owner! - std::map<PVRRECORD_INSTANTRECORDACTION, int> m_actions; - }; - - InstantRecordingActionSelector::InstantRecordingActionSelector(int iInstantRecordTime) - : m_iInstantRecordTime(iInstantRecordTime), - m_pDlgSelect(CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(WINDOW_DIALOG_SELECT)) - { - if (m_pDlgSelect) - { - m_pDlgSelect->Reset(); - m_pDlgSelect->SetMultiSelection(false); - m_pDlgSelect->SetHeading(CVariant{19086}); // Instant recording action - } - else - { - CLog::LogF(LOGERROR, "Unable to obtain WINDOW_DIALOG_SELECT instance"); - } - } - - void InstantRecordingActionSelector::AddAction(PVRRECORD_INSTANTRECORDACTION eAction, const std::string& title) - { - if (m_actions.find(eAction) == m_actions.end()) - { - switch (eAction) - { - case RECORD_INSTANTRECORDTIME: - m_pDlgSelect->Add(StringUtils::Format( - g_localizeStrings.Get(19090), - m_iInstantRecordTime)); // Record next <default duration> minutes - break; - case RECORD_30_MINUTES: - m_pDlgSelect->Add( - StringUtils::Format(g_localizeStrings.Get(19090), 30)); // Record next 30 minutes - break; - case RECORD_60_MINUTES: - m_pDlgSelect->Add( - StringUtils::Format(g_localizeStrings.Get(19090), 60)); // Record next 60 minutes - break; - case RECORD_120_MINUTES: - m_pDlgSelect->Add( - StringUtils::Format(g_localizeStrings.Get(19090), 120)); // Record next 120 minutes - break; - case RECORD_CURRENT_SHOW: - m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19091), - title)); // Record current show (<title>) - break; - case RECORD_NEXT_SHOW: - m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19092), - title)); // Record next show (<title>) - break; - case NONE: - case ASK: - default: - return; - } - - m_actions.insert(std::make_pair(eAction, static_cast<int>(m_actions.size()))); - } - } - - void InstantRecordingActionSelector::PreSelectAction(PVRRECORD_INSTANTRECORDACTION eAction) - { - const auto& it = m_actions.find(eAction); - if (it != m_actions.end()) - m_pDlgSelect->SetSelected(it->second); - } - - PVRRECORD_INSTANTRECORDACTION InstantRecordingActionSelector::Select() - { - PVRRECORD_INSTANTRECORDACTION eAction = NONE; - - m_pDlgSelect->Open(); - - if (m_pDlgSelect->IsConfirmed()) - { - int iSelection = m_pDlgSelect->GetSelectedItem(); - const auto it = - std::find_if(m_actions.cbegin(), m_actions.cend(), - [iSelection](const auto& action) { return action.second == iSelection; }); - - if (it != m_actions.cend()) - eAction = (*it).first; - } - - return eAction; - } - - } // unnamed namespace - - bool CPVRGUIActions::ToggleRecordingOnPlayingChannel() - { - const std::shared_ptr<CPVRChannel> channel = CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel(); - if (channel && channel->CanRecord()) - return SetRecordingOnChannel(channel, !CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel)); - - return false; - } - - bool CPVRGUIActions::SetRecordingOnChannel(const std::shared_ptr<CPVRChannel>& channel, bool bOnOff) - { - bool bReturn = false; - - if (!channel) - return bReturn; - - if (CheckParentalLock(channel) != ParentalCheckResult::SUCCESS) - return bReturn; - - const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(channel->ClientID()); - if (client && client->GetClientCapabilities().SupportsTimers()) - { - /* timers are supported on this channel */ - if (bOnOff && !CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel)) - { - std::shared_ptr<CPVREpgInfoTag> epgTag; - int iDuration = m_settings.GetIntValue(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME); - - int iAction = m_settings.GetIntValue(CSettings::SETTING_PVRRECORD_INSTANTRECORDACTION); - switch (iAction) - { - case RECORD_CURRENT_SHOW: - epgTag = channel->GetEPGNow(); - break; - - case RECORD_INSTANTRECORDTIME: - epgTag.reset(); - break; - - case ASK: - { - PVRRECORD_INSTANTRECORDACTION ePreselect = RECORD_INSTANTRECORDTIME; - const int iDurationDefault = m_settings.GetIntValue(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME); - InstantRecordingActionSelector selector(iDurationDefault); - std::shared_ptr<CPVREpgInfoTag> epgTagNext; - - // fixed length recordings - selector.AddAction(RECORD_30_MINUTES, ""); - selector.AddAction(RECORD_60_MINUTES, ""); - selector.AddAction(RECORD_120_MINUTES, ""); - - if (iDurationDefault != 30 && iDurationDefault != 60 && iDurationDefault != 120) - selector.AddAction(RECORD_INSTANTRECORDTIME, ""); - - // epg-based recordings - epgTag = channel->GetEPGNow(); - if (epgTag) - { - bool bLocked = CServiceBroker::GetPVRManager().IsParentalLocked(epgTag); - - // "now" - const std::string currentTitle = bLocked ? g_localizeStrings.Get(19266) /* Parental locked */ : epgTag->Title(); - selector.AddAction(RECORD_CURRENT_SHOW, currentTitle); - ePreselect = RECORD_CURRENT_SHOW; - - // "next" - epgTagNext = channel->GetEPGNext(); - if (epgTagNext) - { - const std::string nextTitle = bLocked ? g_localizeStrings.Get(19266) /* Parental locked */ : epgTagNext->Title(); - selector.AddAction(RECORD_NEXT_SHOW, nextTitle); - - // be smart. if current show is almost over, preselect next show. - if (epgTag->ProgressPercentage() > 90.0f) - ePreselect = RECORD_NEXT_SHOW; - } - } - - if (ePreselect == RECORD_INSTANTRECORDTIME) - { - if (iDurationDefault == 30) - ePreselect = RECORD_30_MINUTES; - else if (iDurationDefault == 60) - ePreselect = RECORD_60_MINUTES; - else if (iDurationDefault == 120) - ePreselect = RECORD_120_MINUTES; - } - - selector.PreSelectAction(ePreselect); - - PVRRECORD_INSTANTRECORDACTION eSelected = selector.Select(); - switch (eSelected) - { - case NONE: - return false; // dialog canceled - - case RECORD_30_MINUTES: - iDuration = 30; - epgTag.reset(); - break; - - case RECORD_60_MINUTES: - iDuration = 60; - epgTag.reset(); - break; - - case RECORD_120_MINUTES: - iDuration = 120; - epgTag.reset(); - break; - - case RECORD_INSTANTRECORDTIME: - iDuration = iDurationDefault; - epgTag.reset(); - break; - - case RECORD_CURRENT_SHOW: - break; - - case RECORD_NEXT_SHOW: - epgTag = epgTagNext; - break; - - default: - CLog::LogF(LOGERROR, - "Unknown instant record action selection ({}), defaulting to fixed " - "length recording.", - static_cast<int>(eSelected)); - epgTag.reset(); - break; - } - break; - } - - default: - CLog::LogF(LOGERROR, - "Unknown instant record action setting value ({}), defaulting to fixed " - "length recording.", - iAction); - break; - } - - const std::shared_ptr<CPVRTimerInfoTag> newTimer(epgTag ? CPVRTimerInfoTag::CreateFromEpg(epgTag, false) : CPVRTimerInfoTag::CreateInstantTimerTag(channel, iDuration)); - - if (newTimer) - bReturn = CServiceBroker::GetPVRManager().Timers()->AddTimer(newTimer); - - if (!bReturn) - HELPERS::ShowOKDialogText(CVariant{257}, CVariant{19164}); // "Error", "Could not start recording. Check the log for more information about this message." - } - else if (!bOnOff && CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel)) - { - /* delete active timers */ - bReturn = CServiceBroker::GetPVRManager().Timers()->DeleteTimersOnChannel(channel, true, true); - - if (!bReturn) - HELPERS::ShowOKDialogText(CVariant{257}, CVariant{19170}); // "Error", "Could not stop recording. Check the log for more information about this message." - } - } - - return bReturn; - } - - bool CPVRGUIActions::ToggleTimer(const CFileItemPtr& item) const - { - if (!item->HasEPGInfoTag()) - return false; - - const std::shared_ptr<CPVRTimerInfoTag> timer(CPVRItem(item).GetTimerInfoTag()); - if (timer) - { - if (timer->IsRecording()) - return StopRecording(item); - else - return DeleteTimer(item); - } - else - return AddTimer(item, false); - } - - bool CPVRGUIActions::ToggleTimerState(const CFileItemPtr& item) const - { - if (!item->HasPVRTimerInfoTag()) - return false; - - const std::shared_ptr<CPVRTimerInfoTag> timer(item->GetPVRTimerInfoTag()); - if (timer->m_state == PVR_TIMER_STATE_DISABLED) - timer->m_state = PVR_TIMER_STATE_SCHEDULED; - else - timer->m_state = PVR_TIMER_STATE_DISABLED; - - if (CServiceBroker::GetPVRManager().Timers()->UpdateTimer(timer)) - return true; - - HELPERS::ShowOKDialogText(CVariant{257}, CVariant{19263}); // "Error", "Could not update the timer. Check the log for more information about this message." - return false; - } - - bool CPVRGUIActions::EditTimer(const CFileItemPtr& item) const - { - const std::shared_ptr<CPVRTimerInfoTag> timer(CPVRItem(item).GetTimerInfoTag()); - if (!timer) - { - CLog::LogF(LOGERROR, "No timer!"); - return false; - } - - // clone the timer. - const std::shared_ptr<CPVRTimerInfoTag> newTimer(new CPVRTimerInfoTag); - newTimer->UpdateEntry(timer); - - if (ShowTimerSettings(newTimer) && (!timer->GetTimerType()->IsReadOnly() || timer->GetTimerType()->SupportsEnableDisable())) - { - if (newTimer->GetTimerType() == timer->GetTimerType()) - { - if (CServiceBroker::GetPVRManager().Timers()->UpdateTimer(newTimer)) - return true; - - HELPERS::ShowOKDialogText(CVariant{257}, CVariant{19263}); // "Error", "Could not update the timer. Check the log for more information about this message." - return false; - } - else - { - // timer type changed. delete the original timer, then create the new timer. this order is - // important. for instance, the new timer might be a rule which schedules the original timer. - // deleting the original timer after creating the rule would do literally this and we would - // end up with one timer missing wrt to the rule defined by the new timer. - if (DeleteTimer(timer, timer->IsRecording(), false)) - { - if (AddTimer(newTimer)) - return true; - - // rollback. - return AddTimer(timer); - } - } - } - return false; - } - - bool CPVRGUIActions::EditTimerRule(const CFileItemPtr& item) const - { - const std::shared_ptr<CFileItem> parentTimer = GetTimerRule(item); - if (parentTimer) - return EditTimer(parentTimer); - - return false; - } - - std::shared_ptr<CFileItem> CPVRGUIActions::GetTimerRule(const std::shared_ptr<CFileItem>& item) const - { - std::shared_ptr<CPVRTimerInfoTag> timer; - if (item && item->HasEPGInfoTag()) - timer = CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(item->GetEPGInfoTag()); - else if (item && item->HasPVRTimerInfoTag()) - timer = item->GetPVRTimerInfoTag(); - - if (timer) - { - timer = CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer); - if (timer) - return std::make_shared<CFileItem>(timer); - } - return {}; - } - - bool CPVRGUIActions::DeleteTimer(const CFileItemPtr& item) const - { - return DeleteTimer(item, false, false); - } - - bool CPVRGUIActions::DeleteTimerRule(const CFileItemPtr& item) const - { - return DeleteTimer(item, false, true); - } - - bool CPVRGUIActions::DeleteTimer(const CFileItemPtr& item, bool bIsRecording, bool bDeleteRule) const - { - std::shared_ptr<CPVRTimerInfoTag> timer; - const std::shared_ptr<CPVRRecording> recording(CPVRItem(item).GetRecording()); - if (recording) - timer = recording->GetRecordingTimer(); - - if (!timer) - timer = CPVRItem(item).GetTimerInfoTag(); - - if (!timer) - { - CLog::LogF(LOGERROR, "No timer!"); - return false; - } - - if (bDeleteRule && !timer->IsTimerRule()) - timer = CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer); - - if (!timer) - { - CLog::LogF(LOGERROR, "No timer rule!"); - return false; - } - - if (bIsRecording) - { - if (ConfirmStopRecording(timer)) - { - if (CServiceBroker::GetPVRManager().Timers()->DeleteTimer(timer, true, false) == TimerOperationResult::OK) - return true; - - HELPERS::ShowOKDialogText(CVariant{257}, CVariant{19170}); // "Error", "Could not stop recording. Check the log for more information about this message." - return false; - } - } - else if (!timer->GetTimerType()->AllowsDelete()) - { - return false; - } - else - { - bool bAlsoDeleteRule(false); - if (ConfirmDeleteTimer(timer, bAlsoDeleteRule)) - return DeleteTimer(timer, false, bAlsoDeleteRule); - } - return false; - } - - bool CPVRGUIActions::DeleteTimer(const std::shared_ptr<CPVRTimerInfoTag>& timer, bool bIsRecording, bool bDeleteRule) const - { - TimerOperationResult result = CServiceBroker::GetPVRManager().Timers()->DeleteTimer(timer, bIsRecording, bDeleteRule); - switch (result) - { - case TimerOperationResult::RECORDING: - { - // recording running. ask the user if it should be deleted anyway - if (HELPERS::ShowYesNoDialogText( - CVariant{122}, // "Confirm delete" - CVariant{ - 19122}) // "This timer is still recording. Are you sure you want to delete this timer?" - != HELPERS::DialogResponse::CHOICE_YES) - return false; - - return DeleteTimer(timer, true, bDeleteRule); - } - case TimerOperationResult::OK: - { - return true; - } - case TimerOperationResult::FAILED: - { - HELPERS::ShowOKDialogText(CVariant{257}, CVariant{19110}); // "Error", "Could not delete the timer. Check the log for more information about this message." - return false; - } - default: - { - CLog::LogF(LOGERROR, "Unhandled TimerOperationResult ({})!", static_cast<int>(result)); - break; - } - } - return false; - } - - bool CPVRGUIActions::ConfirmDeleteTimer(const std::shared_ptr<CPVRTimerInfoTag>& timer, bool& bDeleteRule) const - { - bool bConfirmed(false); - const std::shared_ptr<CPVRTimerInfoTag> parentTimer(CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer)); - - if (parentTimer && parentTimer->GetTimerType()->AllowsDelete()) - { - // timer was scheduled by a deletable timer rule. prompt user for confirmation for deleting the timer rule, including scheduled timers. - bool bCancel(false); - bDeleteRule = CGUIDialogYesNo::ShowAndGetInput(CVariant{122}, // "Confirm delete" - CVariant{840}, // "Do you want to delete only this timer or also the timer rule that has scheduled it?" - CVariant{""}, - CVariant{timer->Title()}, - bCancel, - CVariant{841}, // "Only this" - CVariant{593}, // "All" - 0); // no autoclose - bConfirmed = !bCancel; - } - else - { - bDeleteRule = false; - - // prompt user for confirmation for deleting the timer - bConfirmed = CGUIDialogYesNo::ShowAndGetInput(CVariant{122}, // "Confirm delete" - timer->IsTimerRule() - ? CVariant{845} // "Are you sure you want to delete this timer rule and all timers it has scheduled?" - : CVariant{846}, // "Are you sure you want to delete this timer?" - CVariant{""}, - CVariant{timer->Title()}); - } - - return bConfirmed; - } - - bool CPVRGUIActions::StopRecording(const CFileItemPtr& item) const - { - if (!DeleteTimer(item, true, false)) - return false; - - CServiceBroker::GetPVRManager().TriggerRecordingsUpdate(); - return true; - } - - bool CPVRGUIActions::ConfirmStopRecording(const std::shared_ptr<CPVRTimerInfoTag>& timer) const - { - return CGUIDialogYesNo::ShowAndGetInput(CVariant{847}, // "Confirm stop recording" - CVariant{848}, // "Are you sure you want to stop this recording?" - CVariant{""}, - CVariant{timer->Title()}); - } - - bool CPVRGUIActions::EditRecording(const CFileItemPtr& item) const - { - const std::shared_ptr<CPVRRecording> recording = CPVRItem(item).GetRecording(); - if (!recording) - { - CLog::LogF(LOGERROR, "No recording!"); - return false; - } - - std::shared_ptr<CPVRRecording> origRecording(new CPVRRecording); - origRecording->Update(*recording, - *CServiceBroker::GetPVRManager().GetClient(recording->m_iClientId)); - - if (!ShowRecordingSettings(recording)) - return false; - - if (origRecording->m_strTitle != recording->m_strTitle) - { - if (!AsyncRenameRecording(recording->m_strTitle).Execute(item)) - CLog::LogF(LOGERROR, "Renaming recording failed!"); - } - - if (origRecording->GetLocalPlayCount() != recording->GetLocalPlayCount()) - { - if (!AsyncSetRecordingPlayCount().Execute(item)) - CLog::LogF(LOGERROR, "Setting recording playcount failed!"); - } - - if (origRecording->m_iLifetime != recording->m_iLifetime) - { - if (!AsyncSetRecordingLifetime().Execute(item)) - CLog::LogF(LOGERROR, "Setting recording lifetime failed!"); - } - - return true; - } - - bool CPVRGUIActions::CanEditRecording(const CFileItem& item) const - { - return CGUIDialogPVRRecordingSettings::CanEditRecording(item); - } - - bool CPVRGUIActions::DeleteRecording(const CFileItemPtr& item) const - { - if ((!item->IsPVRRecording() && !item->m_bIsFolder) || item->IsParentFolder()) - return false; - - if (!ConfirmDeleteRecording(item)) - return false; - - if (!AsyncDeleteRecording().Execute(item)) - { - HELPERS::ShowOKDialogText(CVariant{257}, CVariant{19111}); // "Error", "PVR backend error. Check the log for more information about this message." - return false; - } - - return true; - } - - bool CPVRGUIActions::ConfirmDeleteRecording(const CFileItemPtr& item) const - { - return CGUIDialogYesNo::ShowAndGetInput(CVariant{122}, // "Confirm delete" - item->m_bIsFolder - ? CVariant{19113} // "Delete all recordings in this folder?" - : item->GetPVRRecordingInfoTag()->IsDeleted() - ? CVariant{19294} // "Remove this deleted recording from trash? This operation cannot be reverted." - : CVariant{19112}, // "Delete this recording?" - CVariant{""}, - CVariant{item->GetLabel()}); - } - - bool CPVRGUIActions::DeleteWatchedRecordings(const std::shared_ptr<CFileItem>& item) const - { - if (!item->m_bIsFolder || item->IsParentFolder()) - return false; - - if (!ConfirmDeleteWatchedRecordings(item)) - return false; - - if (!AsyncDeleteRecording(true).Execute(item)) - { - HELPERS::ShowOKDialogText( - CVariant{257}, - CVariant{ - 19111}); // "Error", "PVR backend error. Check the log for more information about this message." - return false; - } - - return true; - } - - bool CPVRGUIActions::ConfirmDeleteWatchedRecordings(const std::shared_ptr<CFileItem>& item) const - { - return CGUIDialogYesNo::ShowAndGetInput( - CVariant{122}, // "Confirm delete" - CVariant{19328}, // "Delete all watched recordings in this folder?" - CVariant{""}, CVariant{item->GetLabel()}); - } - - bool CPVRGUIActions::DeleteAllRecordingsFromTrash() const - { - if (!ConfirmDeleteAllRecordingsFromTrash()) - return false; - - if (!AsyncEmptyRecordingsTrash().Execute(CFileItemPtr())) - return false; - - return true; - } - - bool CPVRGUIActions::ConfirmDeleteAllRecordingsFromTrash() const - { - return CGUIDialogYesNo::ShowAndGetInput(CVariant{19292}, // "Delete all permanently" - CVariant{19293}); // "Remove all deleted recordings from trash? This operation cannot be reverted." - } - - bool CPVRGUIActions::UndeleteRecording(const CFileItemPtr& item) const - { - if (!item->IsDeletedPVRRecording()) - return false; - - if (!AsyncUndeleteRecording().Execute(item)) - { - HELPERS::ShowOKDialogText(CVariant{257}, CVariant{19111}); // "Error", "PVR backend error. Check the log for more information about this message." - return false; - } - - return true; - } - - bool CPVRGUIActions::ShowRecordingSettings(const std::shared_ptr<CPVRRecording>& recording) const - { - CGUIDialogPVRRecordingSettings* pDlgInfo = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRRecordingSettings>(WINDOW_DIALOG_PVR_RECORDING_SETTING); - if (!pDlgInfo) - { - CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PVR_RECORDING_SETTING!"); - return false; - } - - pDlgInfo->SetRecording(recording); - pDlgInfo->Open(); - - return pDlgInfo->IsConfirmed(); - } - - std::string CPVRGUIActions::GetResumeLabel(const CFileItem& item) const - { - std::string resumeString; - - const std::shared_ptr<CPVRRecording> recording(CPVRItem(CFileItemPtr(new CFileItem(item))).GetRecording()); - if (recording && !recording->IsDeleted()) - { - int positionInSeconds = lrint(recording->GetResumePoint().timeInSeconds); - if (positionInSeconds > 0) - resumeString = StringUtils::Format( - g_localizeStrings.Get(12022), - StringUtils::SecondsToTimeString(positionInSeconds, TIME_FORMAT_HH_MM_SS)); - } - return resumeString; - } - - bool CPVRGUIActions::CheckResumeRecording(const CFileItemPtr& item) const - { - bool bPlayIt(true); - std::string resumeString(GetResumeLabel(*item)); - if (!resumeString.empty()) - { - CContextButtons choices; - choices.Add(CONTEXT_BUTTON_RESUME_ITEM, resumeString); - choices.Add(CONTEXT_BUTTON_PLAY_ITEM, 12021); // Play from beginning - int choice = CGUIDialogContextMenu::ShowAndGetChoice(choices); - if (choice > 0) - item->SetStartOffset(choice == CONTEXT_BUTTON_RESUME_ITEM ? STARTOFFSET_RESUME : 0); - else - bPlayIt = false; // context menu cancelled - } - return bPlayIt; - } - - bool CPVRGUIActions::ResumePlayRecording(const CFileItemPtr& item, bool bFallbackToPlay) const - { - bool bCanResume = !GetResumeLabel(*item).empty(); - if (bCanResume) - { - item->SetStartOffset(STARTOFFSET_RESUME); - } - else - { - if (bFallbackToPlay) - item->SetStartOffset(0); - else - return false; - } - - return PlayRecording(item, false); - } - - void CPVRGUIActions::CheckAndSwitchToFullscreen(bool bFullscreen) const - { - CMediaSettings::GetInstance().SetMediaStartWindowed(!bFullscreen); - - if (bFullscreen) - { - CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()); - CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg); - } - } - - void CPVRGUIActions::StartPlayback(CFileItem* item, - bool bFullscreen, - const CPVRStreamProperties* epgProps) const - { - // Obtain dynamic playback url and properties from the respective pvr client - const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*item); - if (client) - { - CPVRStreamProperties props; - - if (item->IsPVRChannel()) - { - // If this was an EPG Tag to be played as live then PlayEpgTag() will create a channel - // fileitem instead and pass the epg tags props so we use those and skip the client call - if (epgProps) - props = *epgProps; - else - client->GetChannelStreamProperties(item->GetPVRChannelInfoTag(), props); - } - else if (item->IsPVRRecording()) - { - client->GetRecordingStreamProperties(item->GetPVRRecordingInfoTag(), props); - } - else if (item->IsEPG()) - { - if (epgProps) // we already have props from PlayEpgTag() - props = *epgProps; - else - client->GetEpgTagStreamProperties(item->GetEPGInfoTag(), props); - } - - if (props.size()) - { - const std::string url = props.GetStreamURL(); - if (!url.empty()) - item->SetDynPath(url); - - const std::string mime = props.GetStreamMimeType(); - if (!mime.empty()) - { - item->SetMimeType(mime); - item->SetContentLookup(false); - } - - for (const auto& prop : props) - item->SetProperty(prop.first, prop.second); - } - } - - CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY, 0, 0, static_cast<void*>(item)); - CheckAndSwitchToFullscreen(bFullscreen); - } - - bool CPVRGUIActions::PlayRecording(const CFileItemPtr& item, bool bCheckResume) const - { - const std::shared_ptr<CPVRRecording> recording(CPVRItem(item).GetRecording()); - if (!recording) - return false; - - if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRecording(recording)) - { - CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()); - CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg); - return true; - } - - if (!bCheckResume || CheckResumeRecording(item)) - { - CFileItem* itemToPlay = new CFileItem(recording); - itemToPlay->SetStartOffset(item->GetStartOffset()); - StartPlayback(itemToPlay, true); - } - return true; - } - - bool CPVRGUIActions::PlayEpgTag(const CFileItemPtr& item) const - { - const std::shared_ptr<CPVREpgInfoTag> epgTag(CPVRItem(item).GetEpgInfoTag()); - if (!epgTag) - return false; - - if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingEpgTag(epgTag)) - { - CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, - CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()); - CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg); - return true; - } - - // Obtain dynamic playback url and properties from the respective pvr client - const std::shared_ptr<CPVRClient> client = - CServiceBroker::GetPVRManager().GetClient(epgTag->ClientID()); - if (!client) - return false; - - CPVRStreamProperties props; - client->GetEpgTagStreamProperties(epgTag, props); - - CFileItem* itemToPlay = nullptr; - if (props.EPGPlaybackAsLive()) - { - const std::shared_ptr<CPVRChannelGroupMember> groupMember = GetChannelGroupMember(*item); - if (!groupMember) - return false; - - itemToPlay = new CFileItem(groupMember); - } - else - { - itemToPlay = new CFileItem(epgTag); - } - - StartPlayback(itemToPlay, true, &props); - return true; - } - - bool CPVRGUIActions::SwitchToChannel(const CFileItemPtr& item, bool bCheckResume) const - { - if (item->m_bIsFolder) - return false; - - std::shared_ptr<CPVRRecording> recording; - const std::shared_ptr<CPVRChannel> channel(CPVRItem(item).GetChannel()); - if (channel) - { - bool bSwitchToFullscreen = CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingChannel(channel); - - if (!bSwitchToFullscreen) - { - recording = CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(channel->GetEPGNow()); - bSwitchToFullscreen = recording && CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRecording(recording); - } - - if (bSwitchToFullscreen) - { - CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()); - CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg); - return true; - } - } - - ParentalCheckResult result = channel ? CheckParentalLock(channel) : ParentalCheckResult::FAILED; - if (result == ParentalCheckResult::SUCCESS) - { - // switch to channel or if recording present, ask whether to switch or play recording... - if (!recording) - recording = CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(channel->GetEPGNow()); - - if (recording) - { - bool bCancel(false); - bool bPlayRecording = CGUIDialogYesNo::ShowAndGetInput(CVariant{19687}, // "Play recording" - CVariant{""}, - CVariant{12021}, // "Play from beginning" - CVariant{recording->m_strTitle}, - bCancel, - CVariant{19000}, // "Switch to channel" - CVariant{19687}, // "Play recording" - 0); // no autoclose - if (bCancel) - return false; - - if (bPlayRecording) - { - const CFileItemPtr recordingItem(new CFileItem(recording)); - return PlayRecording(recordingItem, bCheckResume); - } - } - - bool bFullscreen; - switch (m_settings.GetIntValue(CSettings::SETTING_PVRPLAYBACK_SWITCHTOFULLSCREENCHANNELTYPES)) - { - case 0: // never - bFullscreen = false; - break; - case 1: // TV channels - bFullscreen = !channel->IsRadio(); - break; - case 2: // Radio channels - bFullscreen = channel->IsRadio(); - break; - case 3: // TV and radio channels - default: - bFullscreen = true; - break; - } - const std::shared_ptr<CPVRChannelGroupMember> groupMember = GetChannelGroupMember(*item); - if (!groupMember) - return false; - - StartPlayback(new CFileItem(groupMember), bFullscreen); - return true; - } - else if (result == ParentalCheckResult::FAILED) - { - const std::string channelName = channel ? channel->ChannelName() : g_localizeStrings.Get(19029); // Channel - const std::string msg = StringUtils::Format( - g_localizeStrings.Get(19035), - channelName); // CHANNELNAME could not be played. Check the log for details. - - CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(19166), msg); // PVR information - } - - return false; - } - - bool CPVRGUIActions::SwitchToChannel(PlaybackType type) const - { - std::shared_ptr<CPVRChannelGroupMember> groupMember; - bool bIsRadio(false); - - // check if the desired PlaybackType is already playing, - // and if not, try to grab the last played channel of this type - switch (type) - { - case PlaybackTypeRadio: - { - if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRadio()) - return true; - - const std::shared_ptr<CPVRChannelGroup> allGroup = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllRadio(); - if (allGroup) - groupMember = allGroup->GetLastPlayedChannelGroupMember(); - - bIsRadio = true; - break; - } - case PlaybackTypeTV: - { - if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingTV()) - return true; - - const std::shared_ptr<CPVRChannelGroup> allGroup = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllTV(); - if (allGroup) - groupMember = allGroup->GetLastPlayedChannelGroupMember(); - - break; - } - default: - if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlaying()) - return true; - - groupMember = - CServiceBroker::GetPVRManager().ChannelGroups()->GetLastPlayedChannelGroupMember(); - break; - } - - // if we have a last played channel, start playback - if (groupMember) - { - return SwitchToChannel(std::make_shared<CFileItem>(groupMember), true); - } - else - { - // if we don't, find the active channel group of the demanded type and play it's first channel - const std::shared_ptr<CPVRChannelGroup> channelGroup = - CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup(bIsRadio); - if (channelGroup) - { - // try to start playback of first channel in this group - const std::vector<std::shared_ptr<CPVRChannelGroupMember>> groupMembers = - channelGroup->GetMembers(); - if (!groupMembers.empty()) - { - return SwitchToChannel(std::make_shared<CFileItem>(*groupMembers.begin()), true); - } - } - } - - CLog::LogF(LOGERROR, - "Could not determine {} channel to playback. No last played channel found, and " - "first channel of active group could also not be determined.", - bIsRadio ? "Radio" : "TV"); - - CGUIDialogKaiToast::QueueNotification( - CGUIDialogKaiToast::Error, - g_localizeStrings.Get(19166), // PVR information - StringUtils::Format( - g_localizeStrings.Get(19035), - g_localizeStrings.Get( - bIsRadio ? 19021 - : 19020))); // Radio/TV could not be played. Check the log for details. - return false; - } - - bool CPVRGUIActions::PlayChannelOnStartup() const - { - int iAction = m_settings.GetIntValue(CSettings::SETTING_LOOKANDFEEL_STARTUPACTION); - if (iAction != STARTUP_ACTION_PLAY_TV && - iAction != STARTUP_ACTION_PLAY_RADIO) - return false; - - bool playRadio = (iAction == STARTUP_ACTION_PLAY_RADIO); - - // get the last played channel or fallback to first channel of all channels group - std::shared_ptr<CPVRChannelGroupMember> groupMember = - CServiceBroker::GetPVRManager().PlaybackState()->GetLastPlayedChannelGroupMember(playRadio); - - if (!groupMember) - { - const std::shared_ptr<CPVRChannelGroup> group = - CServiceBroker::GetPVRManager().ChannelGroups()->Get(playRadio)->GetGroupAll(); - auto channels = group->GetMembers(); - if (channels.empty()) - return false; - - groupMember = channels.front(); - if (!groupMember) - return false; - } - - CLog::Log(LOGINFO, "PVR is starting playback of channel '{}'", - groupMember->Channel()->ChannelName()); - return SwitchToChannel(std::make_shared<CFileItem>(groupMember), true); - } - - bool CPVRGUIActions::PlayMedia(const CFileItemPtr& item) const - { - CFileItemPtr pvrItem(item); - if (URIUtils::IsPVRChannel(item->GetPath()) && !item->HasPVRChannelInfoTag()) - { - const std::shared_ptr<CPVRChannelGroupMember> groupMember = - CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelGroupMemberByPath( - item->GetPath()); - if (groupMember) - pvrItem = std::make_shared<CFileItem>(groupMember); - } - else if (URIUtils::IsPVRRecording(item->GetPath()) && !item->HasPVRRecordingInfoTag()) - pvrItem = std::make_shared<CFileItem>(CServiceBroker::GetPVRManager().Recordings()->GetByPath(item->GetPath())); - - bool bCheckResume = true; - if (item->HasProperty("check_resume")) - bCheckResume = item->GetProperty("check_resume").asBoolean(); - - if (pvrItem && pvrItem->HasPVRChannelInfoTag()) - { - return SwitchToChannel(pvrItem, bCheckResume); - } - else if (pvrItem && pvrItem->HasPVRRecordingInfoTag()) - { - return PlayRecording(pvrItem, bCheckResume); - } - - return false; - } - - bool CPVRGUIActions::HideChannel(const CFileItemPtr& item) const - { - const std::shared_ptr<CPVRChannel> channel(item->GetPVRChannelInfoTag()); - - if (!channel) - return false; - - if (!CGUIDialogYesNo::ShowAndGetInput(CVariant{19054}, // "Hide channel" - CVariant{19039}, // "Are you sure you want to hide this channel?" - CVariant{""}, - CVariant{channel->ChannelName()})) - return false; - - if (!CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(channel->IsRadio())->RemoveFromGroup(channel)) - return false; - - CGUIWindowPVRBase* pvrWindow = dynamic_cast<CGUIWindowPVRBase*>(CServiceBroker::GetGUI()->GetWindowManager().GetWindow(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow())); - if (pvrWindow) - pvrWindow->DoRefresh(); - else - CLog::LogF(LOGERROR, "Called on non-pvr window. No refresh possible."); - - return true; - } - - bool CPVRGUIActions::StartChannelScan() - { - return StartChannelScan(PVR_INVALID_CLIENT_ID); - } - - bool CPVRGUIActions::StartChannelScan(int clientId) - { - if (!CServiceBroker::GetPVRManager().IsStarted() || IsRunningChannelScan()) - return false; - - std::shared_ptr<CPVRClient> scanClient; - std::vector<std::shared_ptr<CPVRClient>> possibleScanClients = CServiceBroker::GetPVRManager().Clients()->GetClientsSupportingChannelScan(); - m_bChannelScanRunning = true; - - if (clientId != PVR_INVALID_CLIENT_ID) - { - const auto it = - std::find_if(possibleScanClients.cbegin(), possibleScanClients.cend(), - [clientId](const auto& client) { return client->GetID() == clientId; }); - - if (it != possibleScanClients.cend()) - scanClient = (*it); - - if (!scanClient) - { - CLog::LogF(LOGERROR, - "Provided client id '{}' could not be found in list of possible scan clients!", - clientId); - m_bChannelScanRunning = false; - return false; - } - } - /* multiple clients found */ - else if (possibleScanClients.size() > 1) - { - CGUIDialogSelect* pDialog= CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(WINDOW_DIALOG_SELECT); - if (!pDialog) - { - CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT!"); - m_bChannelScanRunning = false; - return false; - } - - pDialog->Reset(); - pDialog->SetHeading(CVariant{19119}); // "On which backend do you want to search?" - - for (const auto& client : possibleScanClients) - pDialog->Add(client->GetFriendlyName()); - - pDialog->Open(); - - int selection = pDialog->GetSelectedItem(); - if (selection >= 0) - scanClient = possibleScanClients[selection]; - } - /* one client found */ - else if (possibleScanClients.size() == 1) - { - scanClient = possibleScanClients[0]; - } - /* no clients found */ - else if (!scanClient) - { - HELPERS::ShowOKDialogText(CVariant{19033}, // "Information" - CVariant{19192}); // "None of the connected PVR backends supports scanning for channels." - m_bChannelScanRunning = false; - return false; - } - - /* start the channel scan */ - CLog::LogFC(LOGDEBUG, LOGPVR, "Starting to scan for channels on client {}", - scanClient->GetFriendlyName()); - auto start = std::chrono::steady_clock::now(); - - /* do the scan */ - if (scanClient->StartChannelScan() != PVR_ERROR_NO_ERROR) - HELPERS::ShowOKDialogText(CVariant{257}, // "Error" - CVariant{19193}); // "The channel scan can't be started. Check the log for more information about this message." - - auto end = std::chrono::steady_clock::now(); - auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); - - CLog::LogFC(LOGDEBUG, LOGPVR, "Channel scan finished after {} ms", duration.count()); - - m_bChannelScanRunning = false; - return true; - } - - bool CPVRGUIActions::ProcessSettingsMenuHooks() - { - const CPVRClientMap clients = CServiceBroker::GetPVRManager().Clients()->GetCreatedClients(); - - std::vector<std::pair<std::shared_ptr<CPVRClient>, CPVRClientMenuHook>> settingsHooks; - for (const auto& client : clients) - { - const auto hooks = client.second->GetMenuHooks()->GetSettingsHooks(); - std::transform(hooks.cbegin(), hooks.cend(), std::back_inserter(settingsHooks), - [&client](const auto& hook) { return std::make_pair(client.second, hook); }); - } - - if (settingsHooks.empty()) - { - HELPERS::ShowOKDialogText( - CVariant{19033}, // "Information" - CVariant{ - 19347}); // "None of the active PVR clients does provide client-specific settings." - return true; // no settings hooks, no error - } - - auto selectedHook = settingsHooks.begin(); - - // if there is only one settings hook, execute it directly, otherwise let the user select - if (settingsHooks.size() > 1) - { - CGUIDialogSelect* pDialog= CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(WINDOW_DIALOG_SELECT); - if (!pDialog) - { - CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT!"); - return false; - } - - pDialog->Reset(); - pDialog->SetHeading(CVariant{19196}); // "PVR client specific actions" - - for (const auto& hook : settingsHooks) - { - if (clients.size() == 1) - pDialog->Add(hook.second.GetLabel()); - else - pDialog->Add(hook.first->GetBackendName() + ": " + hook.second.GetLabel()); - } - - pDialog->Open(); - - int selection = pDialog->GetSelectedItem(); - if (selection < 0) - return true; // cancelled - - std::advance(selectedHook, selection); - } - return selectedHook->first->CallSettingsMenuHook(selectedHook->second) == PVR_ERROR_NO_ERROR; - } - - namespace - { - class CPVRGUIDatabaseResetComponentsSelector - { - public: - CPVRGUIDatabaseResetComponentsSelector() = default; - virtual ~CPVRGUIDatabaseResetComponentsSelector() = default; - - bool Select() - { - CGUIDialogSelect* pDlgSelect = - CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>( - WINDOW_DIALOG_SELECT); - if (!pDlgSelect) - { - CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT!"); - return false; - } - - CFileItemList options; - - const std::shared_ptr<CFileItem> itemAll = - std::make_shared<CFileItem>(StringUtils::Format(g_localizeStrings.Get(593))); // All - itemAll->SetPath("all"); - options.Add(itemAll); - - // if channels are cleared, groups, EPG data and providers must also be cleared - const std::shared_ptr<CFileItem> itemChannels = std::make_shared<CFileItem>( - StringUtils::Format("{}, {}, {}, {}", - g_localizeStrings.Get(19019), // Channels - g_localizeStrings.Get(19146), // Groups - g_localizeStrings.Get(19069), // Guide - g_localizeStrings.Get(19334))); // Providers - itemChannels->SetPath("channels"); - itemChannels->Select(true); // preselect this item in dialog - options.Add(itemChannels); - - const std::shared_ptr<CFileItem> itemGroups = - std::make_shared<CFileItem>(g_localizeStrings.Get(19146)); // Groups - itemGroups->SetPath("groups"); - options.Add(itemGroups); - - const std::shared_ptr<CFileItem> itemGuide = - std::make_shared<CFileItem>(g_localizeStrings.Get(19069)); // Guide - itemGuide->SetPath("guide"); - options.Add(itemGuide); - - const std::shared_ptr<CFileItem> itemProviders = - std::make_shared<CFileItem>(g_localizeStrings.Get(19334)); // Providers - itemProviders->SetPath("providers"); - options.Add(itemProviders); - - const std::shared_ptr<CFileItem> itemReminders = - std::make_shared<CFileItem>(g_localizeStrings.Get(19215)); // Reminders - itemReminders->SetPath("reminders"); - options.Add(itemReminders); - - const std::shared_ptr<CFileItem> itemRecordings = - std::make_shared<CFileItem>(g_localizeStrings.Get(19017)); // Recordings - itemRecordings->SetPath("recordings"); - options.Add(itemRecordings); - - const std::shared_ptr<CFileItem> itemClients = - std::make_shared<CFileItem>(g_localizeStrings.Get(24019)); // PVR clients - itemClients->SetPath("clients"); - options.Add(itemClients); - - pDlgSelect->Reset(); - pDlgSelect->SetHeading(CVariant{g_localizeStrings.Get(19185)}); // "Clear data" - pDlgSelect->SetItems(options); - pDlgSelect->SetMultiSelection(true); - pDlgSelect->Open(); - - if (!pDlgSelect->IsConfirmed()) - return false; - - for (int i : pDlgSelect->GetSelectedItems()) - { - const std::string path = options.Get(i)->GetPath(); - - m_bResetChannels |= (path == "channels" || path == "all"); - m_bResetGroups |= (path == "groups" || path == "all"); - m_bResetGuide |= (path == "guide" || path == "all"); - m_bResetProviders |= (path == "providers" || path == "all"); - m_bResetReminders |= (path == "reminders" || path == "all"); - m_bResetRecordings |= (path == "recordings" || path == "all"); - m_bResetClients |= (path == "clients" || path == "all"); - } - - m_bResetGroups |= m_bResetChannels; - m_bResetGuide |= m_bResetChannels; - m_bResetProviders |= m_bResetChannels; - - return (m_bResetChannels || m_bResetGroups || m_bResetGuide || m_bResetProviders || - m_bResetReminders || m_bResetRecordings || m_bResetClients); - } - - bool IsResetChannelsSelected() const { return m_bResetChannels; } - bool IsResetGroupsSelected() const { return m_bResetGroups; } - bool IsResetGuideSelected() const { return m_bResetGuide; } - bool IsResetProvidersSelected() const { return m_bResetProviders; } - bool IsResetRemindersSelected() const { return m_bResetReminders; } - bool IsResetRecordingsSelected() const { return m_bResetRecordings; } - bool IsResetClientsSelected() const { return m_bResetClients; } - - private: - bool m_bResetChannels = false; - bool m_bResetGroups = false; - bool m_bResetGuide = false; - bool m_bResetProviders = false; - bool m_bResetReminders = false; - bool m_bResetRecordings = false; - bool m_bResetClients = false; - }; - - } // unnamed namespace - - bool CPVRGUIActions::ResetPVRDatabase(bool bResetEPGOnly) - { - CGUIDialogProgress* pDlgProgress = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS); - if (!pDlgProgress) - { - CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PROGRESS!"); - return false; - } - - bool bResetChannels = false; - bool bResetGroups = false; - bool bResetGuide = false; - bool bResetProviders = false; - bool bResetReminders = false; - bool bResetRecordings = false; - bool bResetClients = false; - - if (bResetEPGOnly) - { - if (!CGUIDialogYesNo::ShowAndGetInput( - CVariant{19098}, // "Warning!" - CVariant{19188})) // "All guide data will be cleared. Are you sure?" - return false; - - bResetGuide = true; - } - else - { - if (CheckParentalPIN() != ParentalCheckResult::SUCCESS) - return false; - - CPVRGUIDatabaseResetComponentsSelector selector; - if (!selector.Select()) - return false; - - if (!CGUIDialogYesNo::ShowAndGetInput( - CVariant{19098}, // "Warning!" - CVariant{19186})) // "All selected data will be cleared. ... Are you sure?" - return false; - - bResetChannels = selector.IsResetChannelsSelected(); - bResetGroups = selector.IsResetGroupsSelected(); - bResetGuide = selector.IsResetGuideSelected(); - bResetProviders = selector.IsResetProvidersSelected(); - bResetReminders = selector.IsResetRemindersSelected(); - bResetRecordings = selector.IsResetRecordingsSelected(); - bResetClients = selector.IsResetClientsSelected(); - } - - CDateTime::ResetTimezoneBias(); - - CLog::LogFC(LOGDEBUG, LOGPVR, "PVR clearing {} database", - bResetEPGOnly ? "EPG" : "PVR and EPG"); - - pDlgProgress->SetHeading(CVariant{313}); // "Cleaning database" - pDlgProgress->SetLine(0, CVariant{g_localizeStrings.Get(19187)}); // "Clearing all related data." - pDlgProgress->SetLine(1, CVariant{""}); - pDlgProgress->SetLine(2, CVariant{""}); - - pDlgProgress->Open(); - pDlgProgress->Progress(); - - if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlaying()) - { - CLog::Log(LOGINFO, "PVR is stopping playback for {} database reset", - bResetEPGOnly ? "EPG" : "PVR and EPG"); - CServiceBroker::GetAppMessenger()->SendMsg(TMSG_MEDIA_STOP); - } - - const std::shared_ptr<CPVRDatabase> pvrDatabase(CServiceBroker::GetPVRManager().GetTVDatabase()); - const std::shared_ptr<CPVREpgDatabase> epgDatabase(CServiceBroker::GetPVRManager().EpgContainer().GetEpgDatabase()); - - // increase db open refcounts, so they don't get closed during following pvr manager shutdown - pvrDatabase->Open(); - epgDatabase->Open(); - - // stop pvr manager; close both pvr and epg databases - CServiceBroker::GetPVRManager().Stop(); - - const int iProgressStepPercentage = - 100 / ((2 * bResetChannels) + bResetGroups + bResetGuide + bResetProviders + - bResetReminders + bResetRecordings + bResetClients + 1); - int iProgressStepsDone = 0; - - if (bResetProviders) - { - pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); - pDlgProgress->Progress(); - - // delete all providers - pvrDatabase->DeleteProviders(); - } - - if (bResetGuide) - { - pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); - pDlgProgress->Progress(); - - // reset channel's EPG pointers - pvrDatabase->ResetEPG(); - - // delete all entries from the EPG database - epgDatabase->DeleteEpg(); - } - - if (bResetGroups) - { - pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); - pDlgProgress->Progress(); - - // delete all channel groups (including data only available locally, like user defined groups) - pvrDatabase->DeleteChannelGroups(); - } - - if (bResetChannels) - { - pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); - pDlgProgress->Progress(); - - // delete all channels (including data only available locally, like user set icons) - pvrDatabase->DeleteChannels(); - } - - if (bResetReminders) - { - pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); - pDlgProgress->Progress(); - - // delete all timers data (e.g. all reminders, which are only stored locally) - pvrDatabase->DeleteTimers(); - } - - if (bResetClients) - { - pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); - pDlgProgress->Progress(); - - // delete all clients data (e.g priorities, which are only stored locally) - pvrDatabase->DeleteClients(); - } - - if (bResetChannels || bResetRecordings) - { - CVideoDatabase videoDatabase; - - if (videoDatabase.Open()) - { - if (bResetChannels) - { - pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); - pDlgProgress->Progress(); - - // delete all channel's entries (e.g. settings, bookmarks, stream details) - videoDatabase.EraseAllForPath("pvr://channels/"); - } - - if (bResetRecordings) - { - pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); - pDlgProgress->Progress(); - - // delete all recording's entries (e.g. settings, bookmarks, stream details) - videoDatabase.EraseAllForPath(CPVRRecordingsPath::PATH_RECORDINGS); - } - - videoDatabase.Close(); - } - } - - // decrease db open refcounts; this actually closes dbs because refcounts drops to zero - pvrDatabase->Close(); - epgDatabase->Close(); - - CLog::LogFC(LOGDEBUG, LOGPVR, "{} database cleared", bResetEPGOnly ? "EPG" : "PVR and EPG"); - - CLog::Log(LOGINFO, "Restarting the PVR Manager after {} database reset", - bResetEPGOnly ? "EPG" : "PVR and EPG"); - CServiceBroker::GetPVRManager().Start(); - - pDlgProgress->SetPercentage(100); - pDlgProgress->Close(); - return true; - } - - ParentalCheckResult CPVRGUIActions::CheckParentalLock(const std::shared_ptr<CPVRChannel>& channel) const - { - if (!CServiceBroker::GetPVRManager().IsParentalLocked(channel)) - return ParentalCheckResult::SUCCESS; - - ParentalCheckResult ret = CheckParentalPIN(); - - if (ret == ParentalCheckResult::FAILED) - CLog::LogF(LOGERROR, "Parental lock verification failed for channel '{}': wrong PIN entered.", - channel->ChannelName()); - - return ret; - } - - ParentalCheckResult CPVRGUIActions::CheckParentalPIN() const - { - if (!m_settings.GetBoolValue(CSettings::SETTING_PVRPARENTAL_ENABLED)) - return ParentalCheckResult::SUCCESS; - - std::string pinCode = m_settings.GetStringValue(CSettings::SETTING_PVRPARENTAL_PIN); - if (pinCode.empty()) - return ParentalCheckResult::SUCCESS; - - InputVerificationResult ret = CGUIDialogNumeric::ShowAndVerifyInput(pinCode, g_localizeStrings.Get(19262), true); // "Parental control. Enter PIN:" - - if (ret == InputVerificationResult::SUCCESS) - { - CServiceBroker::GetPVRManager().RestartParentalTimer(); - return ParentalCheckResult::SUCCESS; - } - else if (ret == InputVerificationResult::FAILED) - { - HELPERS::ShowOKDialogText(CVariant{19264}, CVariant{19265}); // "Incorrect PIN", "The entered PIN was incorrect." - return ParentalCheckResult::FAILED; - } - else - { - return ParentalCheckResult::CANCELED; - } - } - - bool CPVRGUIActions::CanSystemPowerdown(bool bAskUser /*= true*/) const - { - bool bReturn(true); - if (CServiceBroker::GetPVRManager().IsStarted()) - { - std::shared_ptr<CPVRTimerInfoTag> cause; - if (!AllLocalBackendsIdle(cause)) - { - if (bAskUser) - { - std::string text; - - if (cause) - { - if (cause->IsRecording()) - { - text = StringUtils::Format( - g_localizeStrings.Get(19691), // "PVR is currently recording...." - cause->Title(), cause->ChannelName()); - } - else - { - // Next event is due to a local recording or reminder. - const CDateTime now(CDateTime::GetUTCDateTime()); - const CDateTime start(cause->StartAsUTC()); - const CDateTimeSpan prestart(0, 0, cause->MarginStart(), 0); - - CDateTimeSpan diff(start - now); - diff -= prestart; - int mins = diff.GetSecondsTotal() / 60; - - std::string dueStr; - if (mins > 1) - { - // "%d minutes" - dueStr = StringUtils::Format(g_localizeStrings.Get(19694), mins); - } - else - { - // "about a minute" - dueStr = g_localizeStrings.Get(19695); - } - - text = StringUtils::Format( - cause->IsReminder() - ? g_localizeStrings.Get(19690) // "PVR has scheduled a reminder...." - : g_localizeStrings.Get(19692), // "PVR will start recording...." - cause->Title(), cause->ChannelName(), dueStr); - } - } - else - { - // Next event is due to automatic daily wakeup of PVR. - const CDateTime now(CDateTime::GetUTCDateTime()); - - CDateTime dailywakeuptime; - dailywakeuptime.SetFromDBTime(m_settings.GetStringValue(CSettings::SETTING_PVRPOWERMANAGEMENT_DAILYWAKEUPTIME)); - dailywakeuptime = dailywakeuptime.GetAsUTCDateTime(); - - const CDateTimeSpan diff(dailywakeuptime - now); - int mins = diff.GetSecondsTotal() / 60; - - std::string dueStr; - if (mins > 1) - { - // "%d minutes" - dueStr = StringUtils::Format(g_localizeStrings.Get(19694), mins); - } - else - { - // "about a minute" - dueStr = g_localizeStrings.Get(19695); - } - - text = StringUtils::Format(g_localizeStrings.Get(19693), // "Daily wakeup is due in...." - dueStr); - } - - // Inform user about PVR being busy. Ask if user wants to powerdown anyway. - bReturn = - HELPERS::ShowYesNoDialogText(CVariant{19685}, // "Confirm shutdown" - CVariant{text}, CVariant{222}, // "Shutdown anyway", - CVariant{19696}, // "Cancel" - 10000) // timeout value before closing - == HELPERS::DialogResponse::CHOICE_YES; - } - else - bReturn = false; // do not powerdown (busy, but no user interaction requested). - } - } - return bReturn; - } - - bool CPVRGUIActions::AllLocalBackendsIdle(std::shared_ptr<CPVRTimerInfoTag>& causingEvent) const - { - // active recording on local backend? - const std::vector<std::shared_ptr<CPVRTimerInfoTag>> activeRecordings = CServiceBroker::GetPVRManager().Timers()->GetActiveRecordings(); - for (const auto& timer : activeRecordings) - { - if (EventOccursOnLocalBackend(std::make_shared<CFileItem>(timer))) - { - causingEvent = timer; - return false; - } - } - - // soon recording on local backend? - if (IsNextEventWithinBackendIdleTime()) - { - const std::shared_ptr<CPVRTimerInfoTag> timer = CServiceBroker::GetPVRManager().Timers()->GetNextActiveTimer(false); - if (!timer) - { - // Next event is due to automatic daily wakeup of PVR! - causingEvent.reset(); - return false; - } - - if (EventOccursOnLocalBackend(std::make_shared<CFileItem>(timer))) - { - causingEvent = timer; - return false; - } - } - return true; - } - - bool CPVRGUIActions::EventOccursOnLocalBackend(const CFileItemPtr& item) const - { - if (item && item->HasPVRTimerInfoTag()) - { - const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*item); - if (client) - { - const std::string hostname = client->GetBackendHostname(); - if (!hostname.empty() && CServiceBroker::GetNetwork().IsLocalHost(hostname)) - return true; - } - } - return false; - } - - namespace - { - std::string GetAnnouncerText(const std::shared_ptr<CPVRTimerInfoTag>& timer, int idEpg, int idNoEpg) - { - std::string text; - if (timer->IsEpgBased()) - { - text = StringUtils::Format(g_localizeStrings.Get(idEpg), - timer->Title(), // tv show title - timer->ChannelName(), - timer->StartAsLocalTime().GetAsLocalizedDateTime(false, false)); - } - else - { - text = StringUtils::Format(g_localizeStrings.Get(idNoEpg), - timer->ChannelName(), - timer->StartAsLocalTime().GetAsLocalizedDateTime(false, false)); - } - return text; - } - - void AddEventLogEntry(const std::shared_ptr<CPVRTimerInfoTag>& timer, int idEpg, int idNoEpg) - { - std::string name; - std::string icon; - - const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(timer->GetTimerType()->GetClientId()); - if (client) - { - name = client->Name(); - icon = client->Icon(); - } - else - { - name = g_sysinfo.GetAppName(); - icon = "special://xbmc/media/icon256x256.png"; - } - - CPVREventLogJob* job = new CPVREventLogJob; - job->AddEvent(false, // do not display a toast, only log event - false, // info, no error - name, - GetAnnouncerText(timer, idEpg, idNoEpg), - icon); - CServiceBroker::GetJobManager()->AddJob(job, nullptr); - } - } // unnamed namespace - - bool CPVRGUIActions::IsNextEventWithinBackendIdleTime() const - { - // timers going off soon? - const CDateTime now(CDateTime::GetUTCDateTime()); - const CDateTimeSpan idle(0, 0, m_settings.GetIntValue(CSettings::SETTING_PVRPOWERMANAGEMENT_BACKENDIDLETIME), 0); - const CDateTime next(CServiceBroker::GetPVRManager().Timers()->GetNextEventTime()); - const CDateTimeSpan delta(next - now); - - return (delta <= idle); - } - - void CPVRGUIActions::AnnounceReminder(const std::shared_ptr<CPVRTimerInfoTag>& timer) const - { - if (!timer->IsReminder()) - { - CLog::LogF(LOGERROR, "No reminder timer!"); - return; - } - - if (timer->EndAsUTC() < CDateTime::GetUTCDateTime()) - { - // expired. timer end is in the past. write event log entry. - AddEventLogEntry(timer, 19305, 19306); // Deleted missed PVR reminder ... - return; - } - - if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingChannel(timer->Channel())) - { - // no need for an announcement. channel in question is already playing. - return; - } - - // show the reminder dialog - CGUIDialogProgress* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS); - if (!dialog) - return; - - dialog->Reset(); - - dialog->SetHeading(CVariant{19312}); // "PVR reminder" - dialog->ShowChoice(0, CVariant{19165}); // "Switch" - - std::string text = GetAnnouncerText(timer, 19307, 19308); // Reminder for ... - - bool bCanRecord = false; - const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(timer->m_iClientId); - if (client && client->GetClientCapabilities().SupportsTimers()) - { - bCanRecord = true; - dialog->ShowChoice(1, CVariant{264}); // "Record" - dialog->ShowChoice(2, CVariant{222}); // "Cancel" - - if (m_settings.GetBoolValue(CSettings::SETTING_PVRREMINDERS_AUTORECORD)) - text += "\n\n" + g_localizeStrings.Get( - 19309); // (Auto-close of this reminder will schedule a recording...) - else if (m_settings.GetBoolValue(CSettings::SETTING_PVRREMINDERS_AUTOSWITCH)) - text += "\n\n" + g_localizeStrings.Get( - 19331); // (Auto-close of this reminder will switch to channel...) - } - else - { - dialog->ShowChoice(1, CVariant{222}); // "Cancel" - } - - dialog->SetText(text); - dialog->SetPercentage(100); - - dialog->Open(); - - int result = CGUIDialogProgress::CHOICE_NONE; - - static constexpr int PROGRESS_TIMESLICE_MILLISECS = 50; - - const int iWait = m_settings.GetIntValue(CSettings::SETTING_PVRREMINDERS_AUTOCLOSEDELAY) * 1000; - int iRemaining = iWait; - while (iRemaining > 0) - { - result = dialog->GetChoice(); - if (result != CGUIDialogProgress::CHOICE_NONE) - break; - - std::this_thread::sleep_for(std::chrono::milliseconds(PROGRESS_TIMESLICE_MILLISECS)); - - iRemaining -= PROGRESS_TIMESLICE_MILLISECS; - dialog->SetPercentage(iRemaining * 100 / iWait); - dialog->Progress(); - } - - dialog->Close(); - - bool bAutoClosed = (iRemaining <= 0); - bool bSwitch = (result == 0); - bool bRecord = (result == 1); - - if (bAutoClosed) - { - bRecord = (bCanRecord && m_settings.GetBoolValue(CSettings::SETTING_PVRREMINDERS_AUTORECORD)); - bSwitch = m_settings.GetBoolValue(CSettings::SETTING_PVRREMINDERS_AUTOSWITCH); - } - - if (bRecord) - { - std::shared_ptr<CPVRTimerInfoTag> newTimer; - - std::shared_ptr<CPVREpgInfoTag> epgTag = timer->GetEpgInfoTag(); - if (epgTag) - { - newTimer = CPVRTimerInfoTag::CreateFromEpg(epgTag, false); - if (newTimer) - { - // an epgtag can only have max one timer - we need to clear the reminder to be able to - // attach the recording timer - DeleteTimer(timer, false, false); - } - } - else - { - int iDuration = (timer->EndAsUTC() - timer->StartAsUTC()).GetSecondsTotal() / 60; - newTimer = - CPVRTimerInfoTag::CreateTimerTag(timer->Channel(), timer->StartAsUTC(), iDuration); - } - - if (newTimer) - { - // schedule recording - AddTimer(std::make_shared<CFileItem>(newTimer), false); - } - - if (bAutoClosed) - { - AddEventLogEntry(timer, 19310, - 19311); // Scheduled recording for auto-closed PVR reminder ... - } - } - - if (bSwitch) - { - const std::shared_ptr<CPVRChannelGroupMember> groupMember = - GetChannelGroupMember(timer->Channel()); - if (groupMember) - { - SwitchToChannel(std::make_shared<CFileItem>(groupMember), false); - - if (bAutoClosed) - { - AddEventLogEntry(timer, 19332, - 19333); // Switched channel for auto-closed PVR reminder ... - } - } - } - } - - void CPVRGUIActions::AnnounceReminders() const - { - // Prevent multiple yesno dialogs, all on same call stack, due to gui message processing while dialog is open. - if (m_bReminderAnnouncementRunning) - return; - - m_bReminderAnnouncementRunning = true; - std::shared_ptr<CPVRTimerInfoTag> timer = CServiceBroker::GetPVRManager().Timers()->GetNextReminderToAnnnounce(); - while (timer) - { - AnnounceReminder(timer); - timer = CServiceBroker::GetPVRManager().Timers()->GetNextReminderToAnnnounce(); - } - m_bReminderAnnouncementRunning = false; - } - - void CPVRGUIActions::SetSelectedItemPath(bool bRadio, const std::string& path) - { - std::unique_lock<CCriticalSection> lock(m_critSection); - if (bRadio) - m_selectedItemPathRadio = path; - else - m_selectedItemPathTV = path; - } - - std::string CPVRGUIActions::GetSelectedItemPath(bool bRadio) const - { - if (m_settings.GetBoolValue(CSettings::SETTING_PVRMANAGER_PRESELECTPLAYINGCHANNEL)) - { - CPVRManager& mgr = CServiceBroker::GetPVRManager(); - - // if preselect playing channel is activated, return the path of the playing channel, if any. - const std::shared_ptr<CPVRChannel> playingChannel = mgr.PlaybackState()->GetPlayingChannel(); - if (playingChannel && playingChannel->IsRadio() == bRadio) - return GetChannelGroupMember(playingChannel)->Path(); - - const std::shared_ptr<CPVREpgInfoTag> playingTag = mgr.PlaybackState()->GetPlayingEpgTag(); - if (playingTag && playingTag->IsRadio() == bRadio) - { - const std::shared_ptr<CPVRChannel> channel = - mgr.ChannelGroups()->GetChannelForEpgTag(playingTag); - if (channel) - return GetChannelGroupMember(channel)->Path(); - } - } - - std::unique_lock<CCriticalSection> lock(m_critSection); - return bRadio ? m_selectedItemPathRadio : m_selectedItemPathTV; - } - - void CPVRGUIActions::SeekForward() - { - time_t playbackStartTime = CServiceBroker::GetDataCacheCore().GetStartTime(); - if (playbackStartTime > 0) - { - const std::shared_ptr<CPVRChannel> playingChannel = CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel(); - if (playingChannel) - { - time_t nextTime = 0; - std::shared_ptr<CPVREpgInfoTag> next = playingChannel->GetEPGNext(); - if (next) - { - next->StartAsUTC().GetAsTime(nextTime); - } - else - { - // if there is no next event, jump to end of currently playing event - next = playingChannel->GetEPGNow(); - if (next) - next->EndAsUTC().GetAsTime(nextTime); - } - - int64_t seekTime = 0; - if (nextTime != 0) - { - seekTime = (nextTime - playbackStartTime) * 1000; - } - else - { - // no epg; jump to end of buffer - seekTime = CServiceBroker::GetDataCacheCore().GetMaxTime(); - } - CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_SEEK_TIME, seekTime); - } - } - } - - void CPVRGUIActions::SeekBackward(unsigned int iThreshold) - { - time_t playbackStartTime = CServiceBroker::GetDataCacheCore().GetStartTime(); - if (playbackStartTime > 0) - { - const std::shared_ptr<CPVRChannel> playingChannel = CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel(); - if (playingChannel) - { - time_t prevTime = 0; - std::shared_ptr<CPVREpgInfoTag> prev = playingChannel->GetEPGNow(); - if (prev) - { - prev->StartAsUTC().GetAsTime(prevTime); - - // if playback time of current event is above threshold jump to start of current event - int64_t playTime = CServiceBroker::GetDataCacheCore().GetPlayTime() / 1000; - if ((playbackStartTime + playTime - prevTime) <= iThreshold) - { - // jump to start of previous event - prevTime = 0; - prev = playingChannel->GetEPGPrevious(); - if (prev) - prev->StartAsUTC().GetAsTime(prevTime); - } - } - - int64_t seekTime = 0; - if (prevTime != 0) - { - seekTime = (prevTime - playbackStartTime) * 1000; - } - else - { - // no epg; jump to begin of buffer - seekTime = CServiceBroker::GetDataCacheCore().GetMinTime(); - } - CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_SEEK_TIME, seekTime); - } - } - } - - std::shared_ptr<CPVRChannelGroupMember> CPVRGUIActions::GetChannelGroupMember( - const std::shared_ptr<CPVRChannel>& channel) const - { - std::shared_ptr<CPVRChannelGroupMember> groupMember; - if (channel) - { - // first, try whether the channel is contained in the active channel group - std::shared_ptr<CPVRChannelGroup> group = - CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup( - channel->IsRadio()); - if (group) - groupMember = group->GetByUniqueID(channel->StorageId()); - - // as fallback, obtain the member from the 'all channels' group - if (!groupMember) - { - group = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(channel->IsRadio()); - if (group) - groupMember = group->GetByUniqueID(channel->StorageId()); - } - } - return groupMember; - } - - std::shared_ptr<CPVRChannelGroupMember> CPVRGUIActions::GetChannelGroupMember( - const CFileItem& item) const - { - std::shared_ptr<CPVRChannelGroupMember> groupMember = item.GetPVRChannelGroupMemberInfoTag(); - - if (!groupMember) - groupMember = GetChannelGroupMember(CPVRItem(std::make_shared<CFileItem>(item)).GetChannel()); - - return groupMember; - } - - CPVRChannelNumberInputHandler& CPVRGUIActions::GetChannelNumberInputHandler() - { - // window/dialog specific input handler - CPVRChannelNumberInputHandler* windowInputHandler = dynamic_cast<CPVRChannelNumberInputHandler*>(CServiceBroker::GetGUI()->GetWindowManager().GetWindow(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog())); - if (windowInputHandler) - return *windowInputHandler; - - // default - return m_channelNumberInputHandler; - } - - CPVRGUIChannelNavigator& CPVRGUIActions::GetChannelNavigator() - { - return m_channelNavigator; - } - - void CPVRGUIActions::OnPlaybackStarted(const CFileItemPtr& item) - { - const std::shared_ptr<CPVRChannelGroupMember> groupMember = GetChannelGroupMember(*item); - if (groupMember) - { - m_channelNavigator.SetPlayingChannel(groupMember); - SetSelectedItemPath(groupMember->Channel()->IsRadio(), groupMember->Path()); - } - } - - void CPVRGUIActions::OnPlaybackStopped(const CFileItemPtr& item) - { - if (item->HasPVRChannelInfoTag() || item->HasEPGInfoTag()) - { - m_channelNavigator.ClearPlayingChannel(); - } - } - - bool CPVRGUIActions::OnInfo(const std::shared_ptr<CFileItem>& item) - { - if (item->HasPVRRecordingInfoTag()) - { - return ShowRecordingInfo(item); - } - else if (item->HasPVRChannelInfoTag() || item->HasPVRTimerInfoTag()) - { - return ShowEPGInfo(item); - } - else if (item->HasEPGSearchFilter()) - { - return EditSavedSearch(item); - } - return false; - } - - bool CPVRGUIActions::ExecuteSavedSearch(const std::shared_ptr<CFileItem>& item) - { - const auto searchFilter = item->GetEPGSearchFilter(); - - if (!searchFilter) - { - CLog::LogF(LOGERROR, "Wrong item type. No EPG search filter present."); - return false; - } - - CGUIWindowPVRSearchBase* windowSearch = GetSearchWindow(searchFilter->IsRadio()); - if (!windowSearch) - return false; - - windowSearch->SetItemToSearch(item); - CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(windowSearch->GetID()); - return true; - } - - bool CPVRGUIActions::EditSavedSearch(const std::shared_ptr<CFileItem>& item) - { - const auto searchFilter = item->GetEPGSearchFilter(); - - if (!searchFilter) - { - CLog::LogF(LOGERROR, "Wrong item type. No EPG search filter present."); - return false; - } - - CGUIWindowPVRSearchBase* windowSearch = GetSearchWindow(searchFilter->IsRadio()); - if (!windowSearch) - return false; - - if (windowSearch->OpenDialogSearch(item) == CGUIDialogPVRGuideSearch::Result::SEARCH) - CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(windowSearch->GetID()); - - return true; - } - - bool CPVRGUIActions::RenameSavedSearch(const std::shared_ptr<CFileItem>& item) - { - const auto searchFilter = item->GetEPGSearchFilter(); - - if (!searchFilter) - { - CLog::LogF(LOGERROR, "Wrong item type. No EPG search filter present."); - return false; - } - - std::string title = searchFilter->GetTitle(); - if (CGUIKeyboardFactory::ShowAndGetInput(title, - CVariant{g_localizeStrings.Get(528)}, // "Enter title" - false)) - { - searchFilter->SetTitle(title); - CServiceBroker::GetPVRManager().EpgContainer().PersistSavedSearch(*searchFilter); - return true; - } - return false; - } - - bool CPVRGUIActions::DeleteSavedSearch(const std::shared_ptr<CFileItem>& item) - { - const auto searchFilter = item->GetEPGSearchFilter(); - - if (!searchFilter) - { - CLog::LogF(LOGERROR, "Wrong item type. No EPG search filter present."); - return false; - } - - if (CGUIDialogYesNo::ShowAndGetInput(CVariant{122}, // "Confirm delete" - CVariant{19338}, // "Delete this saved search?" - CVariant{""}, CVariant{item->GetLabel()})) - { - return CServiceBroker::GetPVRManager().EpgContainer().DeleteSavedSearch(*searchFilter); - } - return false; - } - - void CPVRChannelSwitchingInputHandler::AppendChannelNumberCharacter(char cCharacter) - { - // special case. if only a single zero was typed in, switch to previously played channel. - if (GetCurrentDigitCount() == 0 && cCharacter == '0') - { - SwitchToPreviousChannel(); - return; - } - - CPVRChannelNumberInputHandler::AppendChannelNumberCharacter(cCharacter); - } - - void CPVRChannelSwitchingInputHandler::GetChannelNumbers(std::vector<std::string>& channelNumbers) - { - const CPVRManager& pvrMgr = CServiceBroker::GetPVRManager(); - const std::shared_ptr<CPVRChannel> playingChannel = pvrMgr.PlaybackState()->GetPlayingChannel(); - if (playingChannel) - { - const std::shared_ptr<CPVRChannelGroup> group = pvrMgr.ChannelGroups()->GetGroupAll(playingChannel->IsRadio()); - if (group) - group->GetChannelNumbers(channelNumbers); - } - } - - void CPVRChannelSwitchingInputHandler::OnInputDone() - { - CPVRChannelNumber channelNumber = GetChannelNumber(); - if (channelNumber.GetChannelNumber()) - SwitchToChannel(channelNumber); - } - - void CPVRChannelSwitchingInputHandler::SwitchToChannel(const CPVRChannelNumber& channelNumber) - { - if (channelNumber.IsValid() && CServiceBroker::GetPVRManager().PlaybackState()->IsPlaying()) - { - const std::shared_ptr<CPVRChannel> playingChannel = CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel(); - if (playingChannel) - { - bool bRadio = playingChannel->IsRadio(); - const std::shared_ptr<CPVRChannelGroup> group = - CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup(bRadio); - - if (channelNumber != group->GetChannelNumber(playingChannel)) - { - // channel number present in active group? - std::shared_ptr<CPVRChannelGroupMember> groupMember = - group->GetByChannelNumber(channelNumber); - - if (!groupMember) - { - // channel number present in any group? - const CPVRChannelGroups* groupAccess = CServiceBroker::GetPVRManager().ChannelGroups()->Get(bRadio); - const std::vector<std::shared_ptr<CPVRChannelGroup>> groups = groupAccess->GetMembers(true); - for (const auto& currentGroup : groups) - { - if (currentGroup == group) // we have already checked this group - continue; - - groupMember = currentGroup->GetByChannelNumber(channelNumber); - if (groupMember) - break; - } - } - - if (groupMember) - { - CServiceBroker::GetAppMessenger()->PostMsg( - TMSG_GUI_ACTION, WINDOW_INVALID, -1, - static_cast<void*>(new CAction( - ACTION_CHANNEL_SWITCH, static_cast<float>(channelNumber.GetChannelNumber()), - static_cast<float>(channelNumber.GetSubChannelNumber())))); - } - } - } - } - } - - void CPVRChannelSwitchingInputHandler::SwitchToPreviousChannel() - { - const std::shared_ptr<CPVRPlaybackState> playbackState = - CServiceBroker::GetPVRManager().PlaybackState(); - if (playbackState->IsPlaying()) - { - const std::shared_ptr<CPVRChannel> playingChannel = playbackState->GetPlayingChannel(); - if (playingChannel) - { - const std::shared_ptr<CPVRChannelGroupMember> groupMember = - playbackState->GetPreviousToLastPlayedChannelGroupMember(playingChannel->IsRadio()); - if (groupMember) - { - const CPVRChannelNumber channelNumber = groupMember->ChannelNumber(); - CServiceBroker::GetAppMessenger()->SendMsg( - TMSG_GUI_ACTION, WINDOW_INVALID, -1, - static_cast<void*>(new CAction( - ACTION_CHANNEL_SWITCH, static_cast<float>(channelNumber.GetChannelNumber()), - static_cast<float>(channelNumber.GetSubChannelNumber())))); - } - } - } - } - -} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActions.h b/xbmc/pvr/guilib/PVRGUIActions.h deleted file mode 100644 index 5635b55ed0..0000000000 --- a/xbmc/pvr/guilib/PVRGUIActions.h +++ /dev/null @@ -1,605 +0,0 @@ -/* - * Copyright (C) 2016-2018 Team Kodi - * This file is part of Kodi - https://kodi.tv - * - * SPDX-License-Identifier: GPL-2.0-or-later - * See LICENSES/README.md for more information. - */ - -#pragma once - -#include "pvr/PVRChannelNumberInputHandler.h" -#include "pvr/guilib/PVRGUIChannelNavigator.h" -#include "pvr/settings/PVRSettings.h" -#include "threads/CriticalSection.h" - -#include <memory> -#include <string> -#include <vector> - -class CFileItem; - -class CGUIWindow; - -namespace PVR -{ - enum PlaybackType - { - PlaybackTypeAny = 0, - PlaybackTypeTV, - PlaybackTypeRadio - }; - - enum class ParentalCheckResult - { - CANCELED, - FAILED, - SUCCESS - }; - - class CPVRChannel; - class CPVRChannelGroupMember; - class CPVRRecording; - class CPVRStreamProperties; - class CPVRTimerInfoTag; - - class CPVRChannelSwitchingInputHandler : public CPVRChannelNumberInputHandler - { - public: - // CPVRChannelNumberInputHandler implementation - void GetChannelNumbers(std::vector<std::string>& channelNumbers) override; - void AppendChannelNumberCharacter(char cCharacter) override; - void OnInputDone() override; - - private: - /*! - * @brief Switch to the channel with the given number. - * @param channelNumber the channel number - */ - void SwitchToChannel(const CPVRChannelNumber& channelNumber); - - /*! - * @brief Switch to the previously played channel. - */ - void SwitchToPreviousChannel(); - }; - - class CPVRGUIActions - { - public: - CPVRGUIActions(); - virtual ~CPVRGUIActions() = default; - - /*! - * @brief Open a dialog with epg information for a given item. - * @param item containing epg data to show. item must be an epg tag, a channel or a timer. - * @return true on success, false otherwise. - */ - bool ShowEPGInfo(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Open a dialog with the epg list for a given item. - * @param item containing channel info. item must be an epg tag, a channel or a timer. - * @return true on success, false otherwise. - */ - bool ShowChannelEPG(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Open a window containing a list of epg tags 'similar' to a given item. - * @param item containing epg data for matching. item must be an epg tag, a channel or a recording. - * @return true on success, false otherwise. - */ - bool FindSimilar(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Open the timer settings dialog to create a new tv or radio timer. - * @param bRadio indicates whether a radio or tv timer shall be created. - * @return true on success, false otherwise. - */ - bool AddTimer(bool bRadio) const; - - /*! - * @brief Create a new timer, either interactive or non-interactive. - * @param item containing epg data to create a timer for. item must be an epg tag or a channel. - * @param bShowTimerSettings is used to control whether a settings dialog will be opened prior creating the timer. - * @return true, if the timer was created successfully, false otherwise. - */ - bool AddTimer(const std::shared_ptr<CFileItem>& item, bool bShowTimerSettings) const; - - /*! - * @brief Add a timer to the client. Doesn't add the timer to the container. The backend will do this. - * @return True if it was sent correctly, false if not. - */ - bool AddTimer(const std::shared_ptr<CPVRTimerInfoTag>& item) const; - - /*! - * @brief Create a new timer rule, either interactive or non-interactive. - * @param item containing epg data to create a timer rule for. item must be an epg tag or a channel. - * @param bShowTimerSettings is used to control whether a settings dialog will be opened prior creating the timer rule. - * @param bFallbackToOneShotTimer if no timer rule can be created, try to create a one-shot timer instead. - * @return true, if the timer rule was created successfully, false otherwise. - */ - bool AddTimerRule(const std::shared_ptr<CFileItem>& item, bool bShowTimerSettings, bool bFallbackToOneShotTimer) const; - - /*! - * @brief Creates or deletes a timer for the given epg tag. - * @param item containing an epg tag. - * @return true on success, false otherwise. - */ - bool ToggleTimer(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Toggles a given timer's enabled/disabled state. - * @param item containing a timer. - * @return true on success, false otherwise. - */ - bool ToggleTimerState(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Open the timer settings dialog to edit an existing timer. - * @param item containing an epg tag or a timer. - * @return true on success, false otherwise. - */ - bool EditTimer(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Open the timer settings dialog to edit an existing timer rule. - * @param item containing an epg tag or a timer. - * @return true on success, false otherwise. - */ - bool EditTimerRule(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Get the timer rule for a given timer - * @param item containing an item to query the timer rule for. item must be a timer or an epg tag. - * @return The timer rule item, or nullptr if none was found. - */ - std::shared_ptr<CFileItem> GetTimerRule(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Delete a timer, always showing a confirmation dialog. - * @param item containing a timer to delete. item must be a timer, an epg tag or a channel. - * @return true, if the timer was deleted successfully, false otherwise. - */ - bool DeleteTimer(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Delete a timer rule, always showing a confirmation dialog. - * @param item containing a timer rule to delete. item must be a timer, an epg tag or a channel. - * @return true, if the timer rule was deleted successfully, false otherwise. - */ - bool DeleteTimerRule(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Open a dialog with information for a given recording. - * @param item containing a recording. - * @return true on success, false otherwise. - */ - bool ShowRecordingInfo(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Toggle recording on the currently playing channel, if any. - * @return True if the recording was started or stopped successfully, false otherwise. - */ - bool ToggleRecordingOnPlayingChannel(); - - /*! - * @brief Start or stop recording on a given channel. - * @param channel the channel to start/stop recording. - * @param bOnOff True to start recording, false to stop. - * @return True if the recording was started or stopped successfully, false otherwise. - */ - bool SetRecordingOnChannel(const std::shared_ptr<CPVRChannel>& channel, bool bOnOff); - - /*! - * @brief Stop a currently active recording, always showing a confirmation dialog. - * @param item containing a recording to stop. item must be a timer, an epg tag or a channel. - * @return true, if the recording was stopped successfully, false otherwise. - */ - bool StopRecording(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Open the recording settings dialog to edit a recording. - * @param item containing the recording to edit. - * @return true on success, false otherwise. - */ - bool EditRecording(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Check if any recording settings can be edited. - * @param item containing the recording to edit. - * @return true on success, false otherwise. - */ - bool CanEditRecording(const CFileItem& item) const; - - /*! - * @brief Delete a recording, always showing a confirmation dialog. - * @param item containing a recording to delete. - * @return true, if the recording was deleted successfully, false otherwise. - */ - bool DeleteRecording(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Delete all watched recordings contained in the given folder, always showing a confirmation dialog. - * @param item containing a recording folder containing the items to delete. - * @return true, if the recordings were deleted successfully, false otherwise. - */ - bool DeleteWatchedRecordings(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Delete all recordings from trash, always showing a confirmation dialog. - * @return true, if the recordings were permanently deleted successfully, false otherwise. - */ - bool DeleteAllRecordingsFromTrash() const; - - /*! - * @brief Undelete a recording. - * @param item containing a recording to undelete. - * @return true, if the recording was undeleted successfully, false otherwise. - */ - bool UndeleteRecording(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Get a localized resume play label, if the given item can be resumed. - * @param item containing a recording or an epg tag. - * @return the localized resume play label that can be used for instance as context menu item label or an empty string if resume is not possible. - */ - std::string GetResumeLabel(const CFileItem& item) const; - - /*! - * @brief Resume a previously not completely played recording. - * @param item containing a recording or an epg tag. - * @param bFallbackToPlay controls whether playback of the recording should be started at the beginning ig no resume data are available. - * @return true on success, false otherwise. - */ - bool ResumePlayRecording(const std::shared_ptr<CFileItem>& item, bool bFallbackToPlay) const; - - /*! - * @brief Play recording. - * @param item containing a recording or an epg tag. - * @param bCheckResume controls resume check. - * @return true on success, false otherwise. - */ - bool PlayRecording(const std::shared_ptr<CFileItem>& item, bool bCheckResume) const; - - /*! - * @brief Play EPG tag. - * @param item containing an epg tag. - * @return true on success, false otherwise. - */ - bool PlayEpgTag(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Switch channel. - * @param item containing a channel or an epg tag. - * @param bCheckResume controls resume check in case a recording for the current epg event is present. - * @return true on success, false otherwise. - */ - bool SwitchToChannel(const std::shared_ptr<CFileItem>& item, bool bCheckResume) const; - - /*! - * @brief Playback the given file item. - * @param item containing a channel or a recording. - * @return True if the item could be played, false otherwise. - */ - bool PlayMedia(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Start playback of the last played channel, and if there is none, play first channel in the current channelgroup. - * @param type The type of playback to be started (any, radio, tv). See PlaybackType enum - * @return True if playback was started, false otherwise. - */ - bool SwitchToChannel(PlaybackType type) const; - - /*! - * @brief Plays the last played channel or the first channel of TV or Radio on startup. - * @return True if playback was started, false otherwise. - */ - bool PlayChannelOnStartup() const; - - /*! - * @brief Hide a channel, always showing a confirmation dialog. - * @param item containing a channel or an epg tag. - * @return true on success, false otherwise. - */ - bool HideChannel(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Open a selection dialog and start a channel scan on the selected client. - * @return true on success, false otherwise. - */ - bool StartChannelScan(); - - /*! - * @brief Start a channel scan on the specified client or open a dialog to select a client - * @param clientId the id of client to scan or PVR_INVALID_CLIENT_ID if a dialog will be opened - * @return true on success, false otherwise. - */ - bool StartChannelScan(int clientId); - - /*! - * @return True when a channel scan is currently running, false otherwise. - */ - bool IsRunningChannelScan() const { return m_bChannelScanRunning; } - - /*! - * @brief Select and invoke client-specific settings actions - * @return true on success, false otherwise. - */ - bool ProcessSettingsMenuHooks(); - - /*! - * @brief Reset the TV database to it's initial state and delete all the data. - * @param bResetEPGOnly True to only reset the EPG database, false to reset both PVR and EPG database. - * @return true on success, false otherwise. - */ - bool ResetPVRDatabase(bool bResetEPGOnly); - - /*! - * @brief Check if channel is parental locked. Ask for PIN if necessary. - * @param channel The channel to do the check for. - * @return the result of the check (success, failed, or canceled by user). - */ - ParentalCheckResult CheckParentalLock(const std::shared_ptr<CPVRChannel>& channel) const; - - /*! - * @brief Open Numeric dialog to check for parental PIN. - * @return the result of the check (success, failed, or canceled by user). - */ - ParentalCheckResult CheckParentalPIN() const; - - /*! - * @brief Check whether the system Kodi is running on can be powered down - * (shutdown/reboot/suspend/hibernate) without stopping any active - * recordings and/or without preventing the start of recordings - * scheduled for now + pvrpowermanagement.backendidletime. - * @param bAskUser True to informs user in case of potential - * data loss. User can decide to allow powerdown anyway. False to - * not to ask user and to not confirm power down. - * @return True if system can be safely powered down, false otherwise. - */ - bool CanSystemPowerdown(bool bAskUser = true) const; - - /*! - * @brief Create a new reminder timer, non-interactive. - * @param item containing epg data to create a reminder timer for. item must be an epg tag. - * @return true, if the timer was created successfully, false otherwise. - */ - bool AddReminder(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Announce due reminders, if any. - */ - void AnnounceReminders() const; - - /*! - * @brief Get the currently selected item path; used across several windows/dialogs to share item selection. - * @param bRadio True to query the selected path for PVR radio, false for Live TV. - * @return the path. - */ - std::string GetSelectedItemPath(bool bRadio) const; - - /*! - * @brief Set the currently selected item path; used across several windows/dialogs to share item selection. - * @param bRadio True to set the selected path for PVR radio, false for Live TV. - * @param path The new path to set. - */ - void SetSelectedItemPath(bool bRadio, const std::string& path); - - /*! - * @brief Seek to the start of the next epg event in timeshift buffer, relative to the currently playing event. - * If there is no next event, seek to the end of the currently playing event (to the 'live' position). - */ - void SeekForward(); - - /*! - * @brief Seek to the start of the previous epg event in timeshift buffer, relative to the currently playing event - * or if there is no previous event or if playback time is greater than given threshold, seek to the start - * of the playing event. - * @param iThreshold the value in seconds to trigger seek to start of current event instead of start of previous event. - */ - void SeekBackward(unsigned int iThreshold); - - /*! - * @brief Get a channel group member for the given channel, either from the currently active - * group or if not found there, from the 'all channels' group. - * @param channel the channel. - * @return the group member or nullptr if not found. - */ - std::shared_ptr<CPVRChannelGroupMember> GetChannelGroupMember( - const std::shared_ptr<CPVRChannel>& channel) const; - - /*! - * @brief Get a channel group member for the given item, either from the currently active group - * or if not found there, from the 'all channels' group. - * @param item the item containing a channel, channel group, recording, timer or epg tag. - * @return the group member or nullptr if not found. - */ - std::shared_ptr<CPVRChannelGroupMember> GetChannelGroupMember(const CFileItem& item) const; - - /*! - * @brief Get the currently active channel number input handler. - * @return the handler. - */ - CPVRChannelNumberInputHandler& GetChannelNumberInputHandler(); - - /*! - * @brief Get the channel navigator. - * @return the navigator. - */ - CPVRGUIChannelNavigator& GetChannelNavigator(); - - /*! - * @brief Inform GUI actions that playback of an item just started. - * @param item The item that started to play. - */ - void OnPlaybackStarted(const std::shared_ptr<CFileItem>& item); - - /*! - * @brief Inform GUI actions that playback of an item was stopped due to user interaction. - * @param item The item that stopped to play. - */ - void OnPlaybackStopped(const std::shared_ptr<CFileItem>& item); - - /*! - * @brief Process info action for the given item. - * @param item The item. - */ - bool OnInfo(const std::shared_ptr<CFileItem>& item); - - /*! - * @brief Execute a saved search. Displays result in search window if it is open. - * @param item The item containing a search filter. - * @return True on success, false otherwise. - */ - bool ExecuteSavedSearch(const std::shared_ptr<CFileItem>& item); - - /*! - * @brief Edit a saved search. Opens the search dialog. - * @param item The item containing a search filter. - * @return True on success, false otherwise. - */ - bool EditSavedSearch(const std::shared_ptr<CFileItem>& item); - - /*! - * @brief Rename a saved search. Opens a title input dialog. - * @param item The item containing a search filter. - * @return True on success, false otherwise. - */ - bool RenameSavedSearch(const std::shared_ptr<CFileItem>& item); - - /*! - * @brief Delete a saved search. Opens confirmation dialog before deleting. - * @param item The item containing a search filter. - * @return True on success, false otherwise. - */ - bool DeleteSavedSearch(const std::shared_ptr<CFileItem>& item); - - private: - CPVRGUIActions(const CPVRGUIActions&) = delete; - CPVRGUIActions const& operator=(CPVRGUIActions const&) = delete; - - /*! - * @brief Open the timer settings dialog. - * @param timer containing the timer the settings shall be displayed for. - * @return true, if the dialog was ended successfully, false otherwise. - */ - bool ShowTimerSettings(const std::shared_ptr<CPVRTimerInfoTag>& timer) const; - - /*! - * @brief Add a timer or timer rule, either interactive or non-interactive. - * @param item containing epg data to create a timer or timer rule for. item must be an epg tag or a channel. - * @param bCreateteRule denotes whether to create a one-shot timer or a timer rule. - * @param bShowTimerSettings is used to control whether a settings dialog will be opened prior creating the timer or timer rule. - * @param bFallbackToOneShotTimer if bCreateteRule is true and no timer rule can be created, try to create a one-shot timer instead. - * @return true, if the timer or timer rule was created successfully, false otherwise. - */ - bool AddTimer(const std::shared_ptr<CFileItem>& item, bool bCreateRule, bool bShowTimerSettings, bool bFallbackToOneShotTimer) const; - - /*! - * @brief Delete a timer or timer rule, always showing a confirmation dialog. - * @param item containing a timer or timer rule to delete. item must be a timer, an epg tag or a channel. - * @param bIsRecording denotes whether the timer is currently recording (controls correct confirmation dialog). - * @param bDeleteRule denotes to delete a timer rule. For convenience, one can pass a timer created by a rule. - * @return true, if the timer or timer rule was deleted successfully, false otherwise. - */ - bool DeleteTimer(const std::shared_ptr<CFileItem>& item, bool bIsRecording, bool bDeleteRule) const; - - /*! - * @brief Delete a timer or timer rule, showing a confirmation dialog in case a timer currently recording shall be deleted. - * @param timer containing a timer or timer rule to delete. - * @param bIsRecording denotes whether the timer is currently recording (controls correct confirmation dialog). - * @param bDeleteRule denotes to delete a timer rule. For convenience, one can pass a timer created by a rule. - * @return true, if the timer or timer rule was deleted successfully, false otherwise. - */ - bool DeleteTimer(const std::shared_ptr<CPVRTimerInfoTag>& timer, bool bIsRecording, bool bDeleteRule) const; - - /*! - * @brief Open a dialog to confirm timer delete. - * @param timer the timer to delete. - * @param bDeleteRule in: ignored - * out, for one shot timer scheduled by a timer rule: true to also delete the timer - * rule that has scheduled this timer, false to only delete the one shot timer. - * out, for one shot timer not scheduled by a timer rule: ignored - * @return true, to proceed with delete, false otherwise. - */ - bool ConfirmDeleteTimer(const std::shared_ptr<CPVRTimerInfoTag>& timer, bool& bDeleteRule) const; - - /*! - * @brief Open a dialog to confirm stop recording. - * @param timer the recording to stop (actually the timer to delete). - * @return true, to proceed with delete, false otherwise. - */ - bool ConfirmStopRecording(const std::shared_ptr<CPVRTimerInfoTag>& timer) const; - - /*! - * @brief Open a dialog to confirm to delete a recording. - * @param item the recording to delete. - * @return true, to proceed with delete, false otherwise. - */ - bool ConfirmDeleteRecording(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Open a dialog to confirm delete all watched recordings contained in the given folder. - * @param item containing a recording folder containing the items to delete. - * @return true, to proceed with delete, false otherwise. - */ - bool ConfirmDeleteWatchedRecordings(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Open a dialog to confirm to permanently remove all deleted recordings. - * @return true, to proceed with delete, false otherwise. - */ - bool ConfirmDeleteAllRecordingsFromTrash() const; - - /*! - * @brief Open the recording settings dialog. - * @param recording containing the recording the settings shall be displayed for. - * @return true, if the dialog was ended successfully, false otherwise. - */ - bool ShowRecordingSettings(const std::shared_ptr<CPVRRecording>& recording) const; - - /*! - * @brief Check whether resume play is possible for a given item, display "resume from ..."/"play from start" context menu in case. - * @param item containing a recording or an epg tag. - * @return true, to play/resume the item, false otherwise. - */ - bool CheckResumeRecording(const std::shared_ptr<CFileItem>& item) const; - - /*! - * @brief Check "play minimized" settings value and switch to fullscreen if not set. - * @param bFullscreen switch to fullscreen or set windowed playback. - */ - void CheckAndSwitchToFullscreen(bool bFullscreen) const; - - /*! - * @brief Start playback of the given item. - * @param bFullscreen start playback fullscreen or not. - * @param epgProps properties to be used instead of calling to the client if supplied. - * @param item containing a channel or a recording. - */ - void StartPlayback(CFileItem* item, - bool bFullscreen, - const CPVRStreamProperties* epgProps = nullptr) const; - - bool AllLocalBackendsIdle(std::shared_ptr<CPVRTimerInfoTag>& causingEvent) const; - bool EventOccursOnLocalBackend(const std::shared_ptr<CFileItem>& item) const; - bool IsNextEventWithinBackendIdleTime() const; - - /*! - * @brief Announce and process a reminder timer. - * @param timer The reminder timer. - */ - void AnnounceReminder(const std::shared_ptr<CPVRTimerInfoTag>& timer) const; - - mutable CCriticalSection m_critSection; - CPVRChannelSwitchingInputHandler m_channelNumberInputHandler; - bool m_bChannelScanRunning = false; - CPVRSettings m_settings; - CPVRGUIChannelNavigator m_channelNavigator; - std::string m_selectedItemPathTV; - std::string m_selectedItemPathRadio; - mutable bool m_bReminderAnnouncementRunning = false; - }; - -} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsChannels.cpp b/xbmc/pvr/guilib/PVRGUIActionsChannels.cpp new file mode 100644 index 0000000000..a3ffce2fea --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsChannels.cpp @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIActionsChannels.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "dialogs/GUIDialogSelect.h" +#include "dialogs/GUIDialogYesNo.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/WindowIDs.h" +#include "input/actions/Action.h" +#include "input/actions/ActionIDs.h" +#include "messaging/ApplicationMessenger.h" +#include "messaging/helpers/DialogOKHelper.h" +#include "pvr/PVRItem.h" +#include "pvr/PVRManager.h" +#include "pvr/PVRPlaybackState.h" +#include "pvr/addons/PVRClient.h" +#include "pvr/addons/PVRClients.h" +#include "pvr/channels/PVRChannel.h" +#include "pvr/channels/PVRChannelGroup.h" +#include "pvr/channels/PVRChannelGroupMember.h" +#include "pvr/channels/PVRChannelGroups.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/guilib/PVRGUIActionsUtils.h" +#include "pvr/windows/GUIWindowPVRBase.h" +#include "utils/Variant.h" +#include "utils/log.h" + +#include <algorithm> +#include <chrono> +#include <memory> +#include <string> +#include <vector> + +using namespace PVR; +using namespace KODI::MESSAGING; + +void CPVRChannelSwitchingInputHandler::AppendChannelNumberCharacter(char cCharacter) +{ + // special case. if only a single zero was typed in, switch to previously played channel. + if (GetCurrentDigitCount() == 0 && cCharacter == '0') + { + SwitchToPreviousChannel(); + return; + } + + CPVRChannelNumberInputHandler::AppendChannelNumberCharacter(cCharacter); +} + +void CPVRChannelSwitchingInputHandler::GetChannelNumbers(std::vector<std::string>& channelNumbers) +{ + const CPVRManager& pvrMgr = CServiceBroker::GetPVRManager(); + const std::shared_ptr<CPVRChannel> playingChannel = pvrMgr.PlaybackState()->GetPlayingChannel(); + if (playingChannel) + { + const std::shared_ptr<CPVRChannelGroup> group = + pvrMgr.ChannelGroups()->GetGroupAll(playingChannel->IsRadio()); + if (group) + group->GetChannelNumbers(channelNumbers); + } +} + +void CPVRChannelSwitchingInputHandler::OnInputDone() +{ + CPVRChannelNumber channelNumber = GetChannelNumber(); + if (channelNumber.GetChannelNumber()) + SwitchToChannel(channelNumber); +} + +void CPVRChannelSwitchingInputHandler::SwitchToChannel(const CPVRChannelNumber& channelNumber) +{ + if (channelNumber.IsValid() && CServiceBroker::GetPVRManager().PlaybackState()->IsPlaying()) + { + const std::shared_ptr<CPVRChannel> playingChannel = + CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel(); + if (playingChannel) + { + bool bRadio = playingChannel->IsRadio(); + const std::shared_ptr<CPVRChannelGroup> group = + CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup(bRadio); + + if (channelNumber != group->GetChannelNumber(playingChannel)) + { + // channel number present in active group? + std::shared_ptr<CPVRChannelGroupMember> groupMember = + group->GetByChannelNumber(channelNumber); + + if (!groupMember) + { + // channel number present in any group? + const CPVRChannelGroups* groupAccess = + CServiceBroker::GetPVRManager().ChannelGroups()->Get(bRadio); + const std::vector<std::shared_ptr<CPVRChannelGroup>> groups = + groupAccess->GetMembers(true); + for (const auto& currentGroup : groups) + { + if (currentGroup == group) // we have already checked this group + continue; + + groupMember = currentGroup->GetByChannelNumber(channelNumber); + if (groupMember) + break; + } + } + + if (groupMember) + { + CServiceBroker::GetAppMessenger()->PostMsg( + TMSG_GUI_ACTION, WINDOW_INVALID, -1, + static_cast<void*>(new CAction( + ACTION_CHANNEL_SWITCH, static_cast<float>(channelNumber.GetChannelNumber()), + static_cast<float>(channelNumber.GetSubChannelNumber())))); + } + } + } + } +} + +void CPVRChannelSwitchingInputHandler::SwitchToPreviousChannel() +{ + const std::shared_ptr<CPVRPlaybackState> playbackState = + CServiceBroker::GetPVRManager().PlaybackState(); + if (playbackState->IsPlaying()) + { + const std::shared_ptr<CPVRChannel> playingChannel = playbackState->GetPlayingChannel(); + if (playingChannel) + { + const std::shared_ptr<CPVRChannelGroupMember> groupMember = + playbackState->GetPreviousToLastPlayedChannelGroupMember(playingChannel->IsRadio()); + if (groupMember) + { + const CPVRChannelNumber channelNumber = groupMember->ChannelNumber(); + CServiceBroker::GetAppMessenger()->SendMsg( + TMSG_GUI_ACTION, WINDOW_INVALID, -1, + static_cast<void*>(new CAction( + ACTION_CHANNEL_SWITCH, static_cast<float>(channelNumber.GetChannelNumber()), + static_cast<float>(channelNumber.GetSubChannelNumber())))); + } + } + } +} + +bool CPVRGUIActionsChannels::HideChannel(const std::shared_ptr<CFileItem>& item) const +{ + const std::shared_ptr<CPVRChannel> channel(item->GetPVRChannelInfoTag()); + + if (!channel) + return false; + + if (!CGUIDialogYesNo::ShowAndGetInput( + CVariant{19054}, // "Hide channel" + CVariant{19039}, // "Are you sure you want to hide this channel?" + CVariant{""}, CVariant{channel->ChannelName()})) + return false; + + if (!CServiceBroker::GetPVRManager() + .ChannelGroups() + ->GetGroupAll(channel->IsRadio()) + ->RemoveFromGroup(channel)) + return false; + + CGUIWindowPVRBase* pvrWindow = + dynamic_cast<CGUIWindowPVRBase*>(CServiceBroker::GetGUI()->GetWindowManager().GetWindow( + CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow())); + if (pvrWindow) + pvrWindow->DoRefresh(); + else + CLog::LogF(LOGERROR, "Called on non-pvr window. No refresh possible."); + + return true; +} + +bool CPVRGUIActionsChannels::StartChannelScan() +{ + return StartChannelScan(PVR_INVALID_CLIENT_ID); +} + +bool CPVRGUIActionsChannels::StartChannelScan(int clientId) +{ + if (!CServiceBroker::GetPVRManager().IsStarted() || IsRunningChannelScan()) + return false; + + std::shared_ptr<CPVRClient> scanClient; + std::vector<std::shared_ptr<CPVRClient>> possibleScanClients = + CServiceBroker::GetPVRManager().Clients()->GetClientsSupportingChannelScan(); + m_bChannelScanRunning = true; + + if (clientId != PVR_INVALID_CLIENT_ID) + { + const auto it = + std::find_if(possibleScanClients.cbegin(), possibleScanClients.cend(), + [clientId](const auto& client) { return client->GetID() == clientId; }); + + if (it != possibleScanClients.cend()) + scanClient = (*it); + + if (!scanClient) + { + CLog::LogF(LOGERROR, + "Provided client id '{}' could not be found in list of possible scan clients!", + clientId); + m_bChannelScanRunning = false; + return false; + } + } + /* multiple clients found */ + else if (possibleScanClients.size() > 1) + { + CGUIDialogSelect* pDialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>( + WINDOW_DIALOG_SELECT); + if (!pDialog) + { + CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT!"); + m_bChannelScanRunning = false; + return false; + } + + pDialog->Reset(); + pDialog->SetHeading(CVariant{19119}); // "On which backend do you want to search?" + + for (const auto& client : possibleScanClients) + pDialog->Add(client->GetFriendlyName()); + + pDialog->Open(); + + int selection = pDialog->GetSelectedItem(); + if (selection >= 0) + scanClient = possibleScanClients[selection]; + } + /* one client found */ + else if (possibleScanClients.size() == 1) + { + scanClient = possibleScanClients[0]; + } + /* no clients found */ + else if (!scanClient) + { + HELPERS::ShowOKDialogText( + CVariant{19033}, // "Information" + CVariant{19192}); // "None of the connected PVR backends supports scanning for channels." + m_bChannelScanRunning = false; + return false; + } + + /* start the channel scan */ + CLog::LogFC(LOGDEBUG, LOGPVR, "Starting to scan for channels on client {}", + scanClient->GetFriendlyName()); + auto start = std::chrono::steady_clock::now(); + + /* do the scan */ + if (scanClient->StartChannelScan() != PVR_ERROR_NO_ERROR) + HELPERS::ShowOKDialogText( + CVariant{257}, // "Error" + CVariant{ + 19193}); // "The channel scan can't be started. Check the log for more information about this message." + + auto end = std::chrono::steady_clock::now(); + auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); + + CLog::LogFC(LOGDEBUG, LOGPVR, "Channel scan finished after {} ms", duration.count()); + + m_bChannelScanRunning = false; + return true; +} + +std::shared_ptr<CPVRChannelGroupMember> CPVRGUIActionsChannels::GetChannelGroupMember( + const std::shared_ptr<CPVRChannel>& channel) const +{ + std::shared_ptr<CPVRChannelGroupMember> groupMember; + if (channel) + { + // first, try whether the channel is contained in the active channel group + std::shared_ptr<CPVRChannelGroup> group = + CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup(channel->IsRadio()); + if (group) + groupMember = group->GetByUniqueID(channel->StorageId()); + + // as fallback, obtain the member from the 'all channels' group + if (!groupMember) + { + group = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(channel->IsRadio()); + if (group) + groupMember = group->GetByUniqueID(channel->StorageId()); + } + } + return groupMember; +} + +std::shared_ptr<CPVRChannelGroupMember> CPVRGUIActionsChannels::GetChannelGroupMember( + const CFileItem& item) const +{ + std::shared_ptr<CPVRChannelGroupMember> groupMember = item.GetPVRChannelGroupMemberInfoTag(); + + if (!groupMember) + groupMember = GetChannelGroupMember(CPVRItem(std::make_shared<CFileItem>(item)).GetChannel()); + + return groupMember; +} + +CPVRChannelNumberInputHandler& CPVRGUIActionsChannels::GetChannelNumberInputHandler() +{ + // window/dialog specific input handler + CPVRChannelNumberInputHandler* windowInputHandler = dynamic_cast<CPVRChannelNumberInputHandler*>( + CServiceBroker::GetGUI()->GetWindowManager().GetWindow( + CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindowOrDialog())); + if (windowInputHandler) + return *windowInputHandler; + + // default + return m_channelNumberInputHandler; +} + +CPVRGUIChannelNavigator& CPVRGUIActionsChannels::GetChannelNavigator() +{ + return m_channelNavigator; +} + +void CPVRGUIActionsChannels::OnPlaybackStarted(const CFileItemPtr& item) +{ + const std::shared_ptr<CPVRChannelGroupMember> groupMember = GetChannelGroupMember(*item); + if (groupMember) + { + m_channelNavigator.SetPlayingChannel(groupMember); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Utils>().SetSelectedItemPath( + groupMember->Channel()->IsRadio(), groupMember->Path()); + } +} + +void CPVRGUIActionsChannels::OnPlaybackStopped(const CFileItemPtr& item) +{ + if (item->HasPVRChannelInfoTag() || item->HasEPGInfoTag()) + { + m_channelNavigator.ClearPlayingChannel(); + } +} diff --git a/xbmc/pvr/guilib/PVRGUIActionsChannels.h b/xbmc/pvr/guilib/PVRGUIActionsChannels.h new file mode 100644 index 0000000000..91fa781839 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsChannels.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "pvr/IPVRComponent.h" +#include "pvr/PVRChannelNumberInputHandler.h" +#include "pvr/guilib/PVRGUIChannelNavigator.h" + +#include <memory> +#include <string> +#include <vector> + +class CFileItem; + +namespace PVR +{ +class CPVRChannel; +class CPVRChannelGroupMember; + +class CPVRChannelSwitchingInputHandler : public CPVRChannelNumberInputHandler +{ +public: + // CPVRChannelNumberInputHandler implementation + void GetChannelNumbers(std::vector<std::string>& channelNumbers) override; + void AppendChannelNumberCharacter(char cCharacter) override; + void OnInputDone() override; + +private: + /*! + * @brief Switch to the channel with the given number. + * @param channelNumber the channel number + */ + void SwitchToChannel(const CPVRChannelNumber& channelNumber); + + /*! + * @brief Switch to the previously played channel. + */ + void SwitchToPreviousChannel(); +}; + +class CPVRGUIActionsChannels : public IPVRComponent +{ +public: + CPVRGUIActionsChannels() = default; + virtual ~CPVRGUIActionsChannels() = default; + + /*! + * @brief Hide a channel, always showing a confirmation dialog. + * @param item containing a channel or an epg tag. + * @return true on success, false otherwise. + */ + bool HideChannel(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Open a selection dialog and start a channel scan on the selected client. + * @return true on success, false otherwise. + */ + bool StartChannelScan(); + + /*! + * @brief Start a channel scan on the specified client or open a dialog to select a client + * @param clientId the id of client to scan or PVR_INVALID_CLIENT_ID if a dialog will be opened + * @return true on success, false otherwise. + */ + bool StartChannelScan(int clientId); + + /*! + * @return True when a channel scan is currently running, false otherwise. + */ + bool IsRunningChannelScan() const { return m_bChannelScanRunning; } + + /*! + * @brief Get a channel group member for the given channel, either from the currently active + * group or if not found there, from the 'all channels' group. + * @param channel the channel. + * @return the group member or nullptr if not found. + */ + std::shared_ptr<CPVRChannelGroupMember> GetChannelGroupMember( + const std::shared_ptr<CPVRChannel>& channel) const; + + /*! + * @brief Get a channel group member for the given item, either from the currently active group + * or if not found there, from the 'all channels' group. + * @param item the item containing a channel, channel group, recording, timer or epg tag. + * @return the group member or nullptr if not found. + */ + std::shared_ptr<CPVRChannelGroupMember> GetChannelGroupMember(const CFileItem& item) const; + + /*! + * @brief Get the currently active channel number input handler. + * @return the handler. + */ + CPVRChannelNumberInputHandler& GetChannelNumberInputHandler(); + + /*! + * @brief Get the channel navigator. + * @return the navigator. + */ + CPVRGUIChannelNavigator& GetChannelNavigator(); + + /*! + * @brief Inform GUI actions that playback of an item just started. + * @param item The item that started to play. + */ + void OnPlaybackStarted(const std::shared_ptr<CFileItem>& item); + + /*! + * @brief Inform GUI actions that playback of an item was stopped due to user interaction. + * @param item The item that stopped to play. + */ + void OnPlaybackStopped(const std::shared_ptr<CFileItem>& item); + +private: + CPVRGUIActionsChannels(const CPVRGUIActionsChannels&) = delete; + CPVRGUIActionsChannels const& operator=(CPVRGUIActionsChannels const&) = delete; + + CPVRChannelSwitchingInputHandler m_channelNumberInputHandler; + bool m_bChannelScanRunning{false}; + CPVRGUIChannelNavigator m_channelNavigator; +}; + +namespace GUI +{ +// pretty scope and name +using Channels = CPVRGUIActionsChannels; +} // namespace GUI + +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsClients.cpp b/xbmc/pvr/guilib/PVRGUIActionsClients.cpp new file mode 100644 index 0000000000..9696d9392e --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsClients.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIActionsClients.h" + +#include "ServiceBroker.h" +#include "dialogs/GUIDialogSelect.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/WindowIDs.h" +#include "messaging/helpers/DialogOKHelper.h" +#include "pvr/PVRManager.h" +#include "pvr/addons/PVRClient.h" +#include "pvr/addons/PVRClientMenuHooks.h" +#include "pvr/addons/PVRClients.h" +#include "utils/Variant.h" +#include "utils/log.h" + +#include <algorithm> +#include <iterator> +#include <memory> +#include <utility> +#include <vector> + +using namespace KODI::MESSAGING; + +using namespace PVR; + +bool CPVRGUIActionsClients::ProcessSettingsMenuHooks() +{ + const CPVRClientMap clients = CServiceBroker::GetPVRManager().Clients()->GetCreatedClients(); + + std::vector<std::pair<std::shared_ptr<CPVRClient>, CPVRClientMenuHook>> settingsHooks; + for (const auto& client : clients) + { + const auto hooks = client.second->GetMenuHooks()->GetSettingsHooks(); + std::transform(hooks.cbegin(), hooks.cend(), std::back_inserter(settingsHooks), + [&client](const auto& hook) { return std::make_pair(client.second, hook); }); + } + + if (settingsHooks.empty()) + { + HELPERS::ShowOKDialogText( + CVariant{19033}, // "Information" + CVariant{19347}); // "None of the active PVR clients does provide client-specific settings." + return true; // no settings hooks, no error + } + + auto selectedHook = settingsHooks.begin(); + + // if there is only one settings hook, execute it directly, otherwise let the user select + if (settingsHooks.size() > 1) + { + CGUIDialogSelect* pDialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>( + WINDOW_DIALOG_SELECT); + if (!pDialog) + { + CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT!"); + return false; + } + + pDialog->Reset(); + pDialog->SetHeading(CVariant{19196}); // "PVR client specific actions" + + for (const auto& hook : settingsHooks) + { + if (clients.size() == 1) + pDialog->Add(hook.second.GetLabel()); + else + pDialog->Add(hook.first->GetBackendName() + ": " + hook.second.GetLabel()); + } + + pDialog->Open(); + + int selection = pDialog->GetSelectedItem(); + if (selection < 0) + return true; // cancelled + + std::advance(selectedHook, selection); + } + return selectedHook->first->CallSettingsMenuHook(selectedHook->second) == PVR_ERROR_NO_ERROR; +} diff --git a/xbmc/pvr/guilib/PVRGUIActionsClients.h b/xbmc/pvr/guilib/PVRGUIActionsClients.h new file mode 100644 index 0000000000..e73d59efc3 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsClients.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "pvr/IPVRComponent.h" + +namespace PVR +{ +class CPVRGUIActionsClients : public IPVRComponent +{ +public: + CPVRGUIActionsClients() = default; + virtual ~CPVRGUIActionsClients() = default; + + /*! + * @brief Select and invoke client-specific settings actions + * @return true on success, false otherwise. + */ + bool ProcessSettingsMenuHooks(); + +private: + CPVRGUIActionsClients(const CPVRGUIActionsClients&) = delete; + CPVRGUIActionsClients const& operator=(CPVRGUIActionsClients const&) = delete; +}; + +namespace GUI +{ +// pretty scope and name +using Clients = CPVRGUIActionsClients; +} // namespace GUI + +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp b/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp new file mode 100644 index 0000000000..53bbf815f6 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIActionsDatabase.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "dialogs/GUIDialogProgress.h" +#include "dialogs/GUIDialogSelect.h" +#include "dialogs/GUIDialogYesNo.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/LocalizeStrings.h" +#include "guilib/WindowIDs.h" +#include "messaging/ApplicationMessenger.h" +#include "pvr/PVRDatabase.h" +#include "pvr/PVRManager.h" +#include "pvr/PVRPlaybackState.h" +#include "pvr/epg/EpgContainer.h" +#include "pvr/epg/EpgDatabase.h" +#include "pvr/guilib/PVRGUIActionsParentalControl.h" +#include "pvr/recordings/PVRRecordings.h" +#include "pvr/recordings/PVRRecordingsPath.h" +#include "utils/StringUtils.h" +#include "utils/Variant.h" +#include "utils/log.h" +#include "video/VideoDatabase.h" + +#include <memory> +#include <string> + +using namespace PVR; + +namespace +{ +class CPVRGUIDatabaseResetComponentsSelector +{ +public: + CPVRGUIDatabaseResetComponentsSelector() = default; + virtual ~CPVRGUIDatabaseResetComponentsSelector() = default; + + bool Select() + { + CGUIDialogSelect* pDlgSelect = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>( + WINDOW_DIALOG_SELECT); + if (!pDlgSelect) + { + CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_SELECT!"); + return false; + } + + CFileItemList options; + + const std::shared_ptr<CFileItem> itemAll = + std::make_shared<CFileItem>(StringUtils::Format(g_localizeStrings.Get(593))); // All + itemAll->SetPath("all"); + options.Add(itemAll); + + // if channels are cleared, groups, EPG data and providers must also be cleared + const std::shared_ptr<CFileItem> itemChannels = + std::make_shared<CFileItem>(StringUtils::Format("{}, {}, {}, {}", + g_localizeStrings.Get(19019), // Channels + g_localizeStrings.Get(19146), // Groups + g_localizeStrings.Get(19069), // Guide + g_localizeStrings.Get(19334))); // Providers + itemChannels->SetPath("channels"); + itemChannels->Select(true); // preselect this item in dialog + options.Add(itemChannels); + + const std::shared_ptr<CFileItem> itemGroups = + std::make_shared<CFileItem>(g_localizeStrings.Get(19146)); // Groups + itemGroups->SetPath("groups"); + options.Add(itemGroups); + + const std::shared_ptr<CFileItem> itemGuide = + std::make_shared<CFileItem>(g_localizeStrings.Get(19069)); // Guide + itemGuide->SetPath("guide"); + options.Add(itemGuide); + + const std::shared_ptr<CFileItem> itemProviders = + std::make_shared<CFileItem>(g_localizeStrings.Get(19334)); // Providers + itemProviders->SetPath("providers"); + options.Add(itemProviders); + + const std::shared_ptr<CFileItem> itemReminders = + std::make_shared<CFileItem>(g_localizeStrings.Get(19215)); // Reminders + itemReminders->SetPath("reminders"); + options.Add(itemReminders); + + const std::shared_ptr<CFileItem> itemRecordings = + std::make_shared<CFileItem>(g_localizeStrings.Get(19017)); // Recordings + itemRecordings->SetPath("recordings"); + options.Add(itemRecordings); + + const std::shared_ptr<CFileItem> itemClients = + std::make_shared<CFileItem>(g_localizeStrings.Get(24019)); // PVR clients + itemClients->SetPath("clients"); + options.Add(itemClients); + + pDlgSelect->Reset(); + pDlgSelect->SetHeading(CVariant{g_localizeStrings.Get(19185)}); // "Clear data" + pDlgSelect->SetItems(options); + pDlgSelect->SetMultiSelection(true); + pDlgSelect->Open(); + + if (!pDlgSelect->IsConfirmed()) + return false; + + for (int i : pDlgSelect->GetSelectedItems()) + { + const std::string path = options.Get(i)->GetPath(); + + m_bResetChannels |= (path == "channels" || path == "all"); + m_bResetGroups |= (path == "groups" || path == "all"); + m_bResetGuide |= (path == "guide" || path == "all"); + m_bResetProviders |= (path == "providers" || path == "all"); + m_bResetReminders |= (path == "reminders" || path == "all"); + m_bResetRecordings |= (path == "recordings" || path == "all"); + m_bResetClients |= (path == "clients" || path == "all"); + } + + m_bResetGroups |= m_bResetChannels; + m_bResetGuide |= m_bResetChannels; + m_bResetProviders |= m_bResetChannels; + + return (m_bResetChannels || m_bResetGroups || m_bResetGuide || m_bResetProviders || + m_bResetReminders || m_bResetRecordings || m_bResetClients); + } + + bool IsResetChannelsSelected() const { return m_bResetChannels; } + bool IsResetGroupsSelected() const { return m_bResetGroups; } + bool IsResetGuideSelected() const { return m_bResetGuide; } + bool IsResetProvidersSelected() const { return m_bResetProviders; } + bool IsResetRemindersSelected() const { return m_bResetReminders; } + bool IsResetRecordingsSelected() const { return m_bResetRecordings; } + bool IsResetClientsSelected() const { return m_bResetClients; } + +private: + bool m_bResetChannels = false; + bool m_bResetGroups = false; + bool m_bResetGuide = false; + bool m_bResetProviders = false; + bool m_bResetReminders = false; + bool m_bResetRecordings = false; + bool m_bResetClients = false; +}; + +} // unnamed namespace + +bool CPVRGUIActionsDatabase::ResetDatabase(bool bResetEPGOnly) +{ + CGUIDialogProgress* pDlgProgress = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>( + WINDOW_DIALOG_PROGRESS); + if (!pDlgProgress) + { + CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PROGRESS!"); + return false; + } + + bool bResetChannels = false; + bool bResetGroups = false; + bool bResetGuide = false; + bool bResetProviders = false; + bool bResetReminders = false; + bool bResetRecordings = false; + bool bResetClients = false; + + if (bResetEPGOnly) + { + if (!CGUIDialogYesNo::ShowAndGetInput( + CVariant{19098}, // "Warning!" + CVariant{19188})) // "All guide data will be cleared. Are you sure?" + return false; + + bResetGuide = true; + } + else + { + if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalPIN() != + ParentalCheckResult::SUCCESS) + return false; + + CPVRGUIDatabaseResetComponentsSelector selector; + if (!selector.Select()) + return false; + + if (!CGUIDialogYesNo::ShowAndGetInput( + CVariant{19098}, // "Warning!" + CVariant{19186})) // "All selected data will be cleared. ... Are you sure?" + return false; + + bResetChannels = selector.IsResetChannelsSelected(); + bResetGroups = selector.IsResetGroupsSelected(); + bResetGuide = selector.IsResetGuideSelected(); + bResetProviders = selector.IsResetProvidersSelected(); + bResetReminders = selector.IsResetRemindersSelected(); + bResetRecordings = selector.IsResetRecordingsSelected(); + bResetClients = selector.IsResetClientsSelected(); + } + + CDateTime::ResetTimezoneBias(); + + CLog::LogFC(LOGDEBUG, LOGPVR, "PVR clearing {} database", bResetEPGOnly ? "EPG" : "PVR and EPG"); + + pDlgProgress->SetHeading(CVariant{313}); // "Cleaning database" + pDlgProgress->SetLine(0, CVariant{g_localizeStrings.Get(19187)}); // "Clearing all related data." + pDlgProgress->SetLine(1, CVariant{""}); + pDlgProgress->SetLine(2, CVariant{""}); + + pDlgProgress->Open(); + pDlgProgress->Progress(); + + if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlaying()) + { + CLog::Log(LOGINFO, "PVR is stopping playback for {} database reset", + bResetEPGOnly ? "EPG" : "PVR and EPG"); + CServiceBroker::GetAppMessenger()->SendMsg(TMSG_MEDIA_STOP); + } + + const std::shared_ptr<CPVRDatabase> pvrDatabase(CServiceBroker::GetPVRManager().GetTVDatabase()); + const std::shared_ptr<CPVREpgDatabase> epgDatabase( + CServiceBroker::GetPVRManager().EpgContainer().GetEpgDatabase()); + + // increase db open refcounts, so they don't get closed during following pvr manager shutdown + pvrDatabase->Open(); + epgDatabase->Open(); + + // stop pvr manager; close both pvr and epg databases + CServiceBroker::GetPVRManager().Stop(); + + const int iProgressStepPercentage = + 100 / ((2 * bResetChannels) + bResetGroups + bResetGuide + bResetProviders + bResetReminders + + bResetRecordings + bResetClients + 1); + int iProgressStepsDone = 0; + + if (bResetProviders) + { + pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); + pDlgProgress->Progress(); + + // delete all providers + pvrDatabase->DeleteProviders(); + } + + if (bResetGuide) + { + pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); + pDlgProgress->Progress(); + + // reset channel's EPG pointers + pvrDatabase->ResetEPG(); + + // delete all entries from the EPG database + epgDatabase->DeleteEpg(); + } + + if (bResetGroups) + { + pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); + pDlgProgress->Progress(); + + // delete all channel groups (including data only available locally, like user defined groups) + pvrDatabase->DeleteChannelGroups(); + } + + if (bResetChannels) + { + pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); + pDlgProgress->Progress(); + + // delete all channels (including data only available locally, like user set icons) + pvrDatabase->DeleteChannels(); + } + + if (bResetReminders) + { + pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); + pDlgProgress->Progress(); + + // delete all timers data (e.g. all reminders, which are only stored locally) + pvrDatabase->DeleteTimers(); + } + + if (bResetClients) + { + pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); + pDlgProgress->Progress(); + + // delete all clients data (e.g priorities, which are only stored locally) + pvrDatabase->DeleteClients(); + } + + if (bResetChannels || bResetRecordings) + { + CVideoDatabase videoDatabase; + + if (videoDatabase.Open()) + { + if (bResetChannels) + { + pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); + pDlgProgress->Progress(); + + // delete all channel's entries (e.g. settings, bookmarks, stream details) + videoDatabase.EraseAllForPath("pvr://channels/"); + } + + if (bResetRecordings) + { + pDlgProgress->SetPercentage(iProgressStepPercentage * ++iProgressStepsDone); + pDlgProgress->Progress(); + + // delete all recording's entries (e.g. settings, bookmarks, stream details) + videoDatabase.EraseAllForPath(CPVRRecordingsPath::PATH_RECORDINGS); + } + + videoDatabase.Close(); + } + } + + // decrease db open refcounts; this actually closes dbs because refcounts drops to zero + pvrDatabase->Close(); + epgDatabase->Close(); + + CLog::LogFC(LOGDEBUG, LOGPVR, "{} database cleared", bResetEPGOnly ? "EPG" : "PVR and EPG"); + + CLog::Log(LOGINFO, "Restarting the PVR Manager after {} database reset", + bResetEPGOnly ? "EPG" : "PVR and EPG"); + CServiceBroker::GetPVRManager().Start(); + + pDlgProgress->SetPercentage(100); + pDlgProgress->Close(); + return true; +} diff --git a/xbmc/pvr/guilib/PVRGUIActionsDatabase.h b/xbmc/pvr/guilib/PVRGUIActionsDatabase.h new file mode 100644 index 0000000000..f4d807fe77 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsDatabase.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "pvr/IPVRComponent.h" + +namespace PVR +{ +class CPVRGUIActionsDatabase : public IPVRComponent +{ +public: + CPVRGUIActionsDatabase() = default; + virtual ~CPVRGUIActionsDatabase() = default; + + /*! + * @brief Reset the TV database to it's initial state and delete all the data. + * @param bResetEPGOnly True to only reset the EPG database, false to reset both PVR and EPG + * database. + * @return true on success, false otherwise. + */ + bool ResetDatabase(bool bResetEPGOnly); + +private: + CPVRGUIActionsDatabase(const CPVRGUIActionsDatabase&) = delete; + CPVRGUIActionsDatabase const& operator=(CPVRGUIActionsDatabase const&) = delete; +}; + +namespace GUI +{ +// pretty scope and name +using Database = CPVRGUIActionsDatabase; +} // namespace GUI + +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsEPG.cpp b/xbmc/pvr/guilib/PVRGUIActionsEPG.cpp new file mode 100644 index 0000000000..d74e822b93 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsEPG.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIActionsEPG.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "dialogs/GUIDialogYesNo.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIKeyboardFactory.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/LocalizeStrings.h" +#include "guilib/WindowIDs.h" +#include "pvr/PVRItem.h" +#include "pvr/PVRManager.h" +#include "pvr/dialogs/GUIDialogPVRChannelGuide.h" +#include "pvr/dialogs/GUIDialogPVRGuideInfo.h" +#include "pvr/epg/EpgContainer.h" +#include "pvr/epg/EpgSearchFilter.h" +#include "pvr/guilib/PVRGUIActionsParentalControl.h" +#include "pvr/windows/GUIWindowPVRSearch.h" +#include "utils/Variant.h" +#include "utils/log.h" + +#include <memory> +#include <string> + +using namespace PVR; + +namespace +{ +PVR::CGUIWindowPVRSearchBase* GetSearchWindow(bool bRadio) +{ + const int windowSearchId = bRadio ? WINDOW_RADIO_SEARCH : WINDOW_TV_SEARCH; + + PVR::CGUIWindowPVRSearchBase* windowSearch; + + CGUIWindowManager& windowMgr = CServiceBroker::GetGUI()->GetWindowManager(); + if (bRadio) + windowSearch = windowMgr.GetWindow<PVR::CGUIWindowPVRRadioSearch>(windowSearchId); + else + windowSearch = windowMgr.GetWindow<PVR::CGUIWindowPVRTVSearch>(windowSearchId); + + if (!windowSearch) + CLog::LogF(LOGERROR, "Unable to get {}!", bRadio ? "WINDOW_RADIO_SEARCH" : "WINDOW_TV_SEARCH"); + + return windowSearch; +} +} // unnamed namespace + +bool CPVRGUIActionsEPG::ShowEPGInfo(const CFileItemPtr& item) const +{ + const std::shared_ptr<CPVRChannel> channel(CPVRItem(item).GetChannel()); + if (channel && CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalLock( + channel) != ParentalCheckResult::SUCCESS) + return false; + + const std::shared_ptr<CPVREpgInfoTag> epgTag(CPVRItem(item).GetEpgInfoTag()); + if (!epgTag) + { + CLog::LogF(LOGERROR, "No epg tag!"); + return false; + } + + CGUIDialogPVRGuideInfo* pDlgInfo = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRGuideInfo>( + WINDOW_DIALOG_PVR_GUIDE_INFO); + if (!pDlgInfo) + { + CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PVR_GUIDE_INFO!"); + return false; + } + + pDlgInfo->SetProgInfo(epgTag); + pDlgInfo->Open(); + return true; +} + +bool CPVRGUIActionsEPG::ShowChannelEPG(const CFileItemPtr& item) const +{ + const std::shared_ptr<CPVRChannel> channel(CPVRItem(item).GetChannel()); + if (channel && CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalLock( + channel) != ParentalCheckResult::SUCCESS) + return false; + + CGUIDialogPVRChannelGuide* pDlgInfo = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRChannelGuide>( + WINDOW_DIALOG_PVR_CHANNEL_GUIDE); + if (!pDlgInfo) + { + CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PVR_CHANNEL_GUIDE!"); + return false; + } + + pDlgInfo->Open(channel); + return true; +} + +bool CPVRGUIActionsEPG::FindSimilar(const std::shared_ptr<CFileItem>& item) const +{ + CGUIWindowPVRSearchBase* windowSearch = GetSearchWindow(CPVRItem(item).IsRadio()); + if (!windowSearch) + return false; + + //! @todo If we want dialogs to spawn program search in a clean way - without having to force-close any + // other dialogs - we must introduce a search dialog with functionality similar to the search window. + + for (int iId = CServiceBroker::GetGUI()->GetWindowManager().GetTopmostModalDialog( + true /* ignoreClosing */); + iId != WINDOW_INVALID; + iId = CServiceBroker::GetGUI()->GetWindowManager().GetTopmostModalDialog( + true /* ignoreClosing */)) + { + CLog::LogF(LOGWARNING, + "Have to close modal dialog with id {} before search window can be opened.", iId); + + CGUIWindow* window = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(iId); + if (window) + { + window->Close(); + } + else + { + CLog::LogF(LOGERROR, "Unable to get window instance {}! Cannot open search window.", iId); + return false; // return, otherwise we run into an endless loop + } + } + + windowSearch->SetItemToSearch(item); + CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(windowSearch->GetID()); + return true; +}; + +bool CPVRGUIActionsEPG::ExecuteSavedSearch(const std::shared_ptr<CFileItem>& item) +{ + const auto searchFilter = item->GetEPGSearchFilter(); + + if (!searchFilter) + { + CLog::LogF(LOGERROR, "Wrong item type. No EPG search filter present."); + return false; + } + + CGUIWindowPVRSearchBase* windowSearch = GetSearchWindow(searchFilter->IsRadio()); + if (!windowSearch) + return false; + + windowSearch->SetItemToSearch(item); + CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(windowSearch->GetID()); + return true; +} + +bool CPVRGUIActionsEPG::EditSavedSearch(const std::shared_ptr<CFileItem>& item) +{ + const auto searchFilter = item->GetEPGSearchFilter(); + + if (!searchFilter) + { + CLog::LogF(LOGERROR, "Wrong item type. No EPG search filter present."); + return false; + } + + CGUIWindowPVRSearchBase* windowSearch = GetSearchWindow(searchFilter->IsRadio()); + if (!windowSearch) + return false; + + if (windowSearch->OpenDialogSearch(item) == CGUIDialogPVRGuideSearch::Result::SEARCH) + CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(windowSearch->GetID()); + + return true; +} + +bool CPVRGUIActionsEPG::RenameSavedSearch(const std::shared_ptr<CFileItem>& item) +{ + const auto searchFilter = item->GetEPGSearchFilter(); + + if (!searchFilter) + { + CLog::LogF(LOGERROR, "Wrong item type. No EPG search filter present."); + return false; + } + + std::string title = searchFilter->GetTitle(); + if (CGUIKeyboardFactory::ShowAndGetInput(title, + CVariant{g_localizeStrings.Get(528)}, // "Enter title" + false)) + { + searchFilter->SetTitle(title); + CServiceBroker::GetPVRManager().EpgContainer().PersistSavedSearch(*searchFilter); + return true; + } + return false; +} + +bool CPVRGUIActionsEPG::DeleteSavedSearch(const std::shared_ptr<CFileItem>& item) +{ + const auto searchFilter = item->GetEPGSearchFilter(); + + if (!searchFilter) + { + CLog::LogF(LOGERROR, "Wrong item type. No EPG search filter present."); + return false; + } + + if (CGUIDialogYesNo::ShowAndGetInput(CVariant{122}, // "Confirm delete" + CVariant{19338}, // "Delete this saved search?" + CVariant{""}, CVariant{item->GetLabel()})) + { + return CServiceBroker::GetPVRManager().EpgContainer().DeleteSavedSearch(*searchFilter); + } + return false; +} diff --git a/xbmc/pvr/guilib/PVRGUIActionsEPG.h b/xbmc/pvr/guilib/PVRGUIActionsEPG.h new file mode 100644 index 0000000000..cbc76ccd17 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsEPG.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "pvr/IPVRComponent.h" + +#include <memory> + +class CFileItem; + +namespace PVR +{ +class CPVRGUIActionsEPG : public IPVRComponent +{ +public: + CPVRGUIActionsEPG() = default; + virtual ~CPVRGUIActionsEPG() = default; + + /*! + * @brief Open a dialog with epg information for a given item. + * @param item containing epg data to show. item must be an epg tag, a channel or a timer. + * @return true on success, false otherwise. + */ + bool ShowEPGInfo(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Open a dialog with the epg list for a given item. + * @param item containing channel info. item must be an epg tag, a channel or a timer. + * @return true on success, false otherwise. + */ + bool ShowChannelEPG(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Open a window containing a list of epg tags 'similar' to a given item. + * @param item containing epg data for matching. item must be an epg tag, a channel or a + * recording. + * @return true on success, false otherwise. + */ + bool FindSimilar(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Execute a saved search. Displays result in search window if it is open. + * @param item The item containing a search filter. + * @return True on success, false otherwise. + */ + bool ExecuteSavedSearch(const std::shared_ptr<CFileItem>& item); + + /*! + * @brief Edit a saved search. Opens the search dialog. + * @param item The item containing a search filter. + * @return True on success, false otherwise. + */ + bool EditSavedSearch(const std::shared_ptr<CFileItem>& item); + + /*! + * @brief Rename a saved search. Opens a title input dialog. + * @param item The item containing a search filter. + * @return True on success, false otherwise. + */ + bool RenameSavedSearch(const std::shared_ptr<CFileItem>& item); + + /*! + * @brief Delete a saved search. Opens confirmation dialog before deleting. + * @param item The item containing a search filter. + * @return True on success, false otherwise. + */ + bool DeleteSavedSearch(const std::shared_ptr<CFileItem>& item); + +private: + CPVRGUIActionsEPG(const CPVRGUIActionsEPG&) = delete; + CPVRGUIActionsEPG const& operator=(CPVRGUIActionsEPG const&) = delete; +}; + +namespace GUI +{ +// pretty scope and name +using EPG = CPVRGUIActionsEPG; +} // namespace GUI + +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsParentalControl.cpp b/xbmc/pvr/guilib/PVRGUIActionsParentalControl.cpp new file mode 100644 index 0000000000..96947c4381 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsParentalControl.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIActionsParentalControl.h" + +#include "ServiceBroker.h" +#include "dialogs/GUIDialogNumeric.h" +#include "guilib/LocalizeStrings.h" +#include "messaging/helpers/DialogOKHelper.h" +#include "pvr/PVRManager.h" +#include "pvr/channels/PVRChannel.h" +#include "settings/Settings.h" +#include "utils/Variant.h" +#include "utils/log.h" + +#include <memory> +#include <string> + +using namespace PVR; +using namespace KODI::MESSAGING; + +CPVRGUIActionsParentalControl::CPVRGUIActionsParentalControl() + : m_settings({CSettings::SETTING_PVRPARENTAL_PIN, CSettings::SETTING_PVRPARENTAL_ENABLED}) +{ +} + +ParentalCheckResult CPVRGUIActionsParentalControl::CheckParentalLock( + const std::shared_ptr<CPVRChannel>& channel) const +{ + if (!CServiceBroker::GetPVRManager().IsParentalLocked(channel)) + return ParentalCheckResult::SUCCESS; + + ParentalCheckResult ret = CheckParentalPIN(); + + if (ret == ParentalCheckResult::FAILED) + CLog::LogF(LOGERROR, "Parental lock verification failed for channel '{}': wrong PIN entered.", + channel->ChannelName()); + + return ret; +} + +ParentalCheckResult CPVRGUIActionsParentalControl::CheckParentalPIN() const +{ + if (!m_settings.GetBoolValue(CSettings::SETTING_PVRPARENTAL_ENABLED)) + return ParentalCheckResult::SUCCESS; + + std::string pinCode = m_settings.GetStringValue(CSettings::SETTING_PVRPARENTAL_PIN); + if (pinCode.empty()) + return ParentalCheckResult::SUCCESS; + + InputVerificationResult ret = CGUIDialogNumeric::ShowAndVerifyInput( + pinCode, g_localizeStrings.Get(19262), true); // "Parental control. Enter PIN:" + + if (ret == InputVerificationResult::SUCCESS) + { + CServiceBroker::GetPVRManager().RestartParentalTimer(); + return ParentalCheckResult::SUCCESS; + } + else if (ret == InputVerificationResult::FAILED) + { + HELPERS::ShowOKDialogText(CVariant{19264}, + CVariant{19265}); // "Incorrect PIN", "The entered PIN was incorrect." + return ParentalCheckResult::FAILED; + } + else + { + return ParentalCheckResult::CANCELED; + } +} diff --git a/xbmc/pvr/guilib/PVRGUIActionsParentalControl.h b/xbmc/pvr/guilib/PVRGUIActionsParentalControl.h new file mode 100644 index 0000000000..47d3ec7509 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsParentalControl.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "pvr/IPVRComponent.h" +#include "pvr/settings/PVRSettings.h" + +#include <memory> + +namespace PVR +{ +enum class ParentalCheckResult +{ + CANCELED, + FAILED, + SUCCESS +}; + +class CPVRChannel; + +class CPVRGUIActionsParentalControl : public IPVRComponent +{ +public: + CPVRGUIActionsParentalControl(); + virtual ~CPVRGUIActionsParentalControl() = default; + + /*! + * @brief Check if channel is parental locked. Ask for PIN if necessary. + * @param channel The channel to do the check for. + * @return the result of the check (success, failed, or canceled by user). + */ + ParentalCheckResult CheckParentalLock(const std::shared_ptr<CPVRChannel>& channel) const; + + /*! + * @brief Open Numeric dialog to check for parental PIN. + * @return the result of the check (success, failed, or canceled by user). + */ + ParentalCheckResult CheckParentalPIN() const; + +private: + CPVRGUIActionsParentalControl(const CPVRGUIActionsParentalControl&) = delete; + CPVRGUIActionsParentalControl const& operator=(CPVRGUIActionsParentalControl const&) = delete; + + CPVRSettings m_settings; +}; + +namespace GUI +{ +// pretty scope and name +using Parental = CPVRGUIActionsParentalControl; +} // namespace GUI + +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp b/xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp new file mode 100644 index 0000000000..19cd2c8822 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp @@ -0,0 +1,561 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIActionsPlayback.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "application/ApplicationEnums.h" +#include "cores/DataCacheCore.h" +#include "dialogs/GUIDialogContextMenu.h" +#include "dialogs/GUIDialogKaiToast.h" +#include "dialogs/GUIDialogYesNo.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/LocalizeStrings.h" +#include "guilib/WindowIDs.h" +#include "messaging/ApplicationMessenger.h" +#include "pvr/PVRItem.h" +#include "pvr/PVRManager.h" +#include "pvr/PVRPlaybackState.h" +#include "pvr/PVRStreamProperties.h" +#include "pvr/addons/PVRClient.h" +#include "pvr/channels/PVRChannel.h" +#include "pvr/channels/PVRChannelGroup.h" +#include "pvr/channels/PVRChannelGroupMember.h" +#include "pvr/channels/PVRChannelGroups.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/epg/EpgInfoTag.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsParentalControl.h" +#include "pvr/recordings/PVRRecording.h" +#include "pvr/recordings/PVRRecordings.h" +#include "settings/MediaSettings.h" +#include "settings/Settings.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "utils/Variant.h" +#include "utils/log.h" + +#include <memory> +#include <string> +#include <vector> + +using namespace PVR; +using namespace KODI::MESSAGING; + +CPVRGUIActionsPlayback::CPVRGUIActionsPlayback() + : m_settings({CSettings::SETTING_LOOKANDFEEL_STARTUPACTION, + CSettings::SETTING_PVRPLAYBACK_SWITCHTOFULLSCREENCHANNELTYPES}) +{ +} + +std::string CPVRGUIActionsPlayback::GetResumeLabel(const CFileItem& item) const +{ + std::string resumeString; + + const std::shared_ptr<CPVRRecording> recording( + CPVRItem(CFileItemPtr(new CFileItem(item))).GetRecording()); + if (recording && !recording->IsDeleted()) + { + int positionInSeconds = lrint(recording->GetResumePoint().timeInSeconds); + if (positionInSeconds > 0) + resumeString = StringUtils::Format( + g_localizeStrings.Get(12022), + StringUtils::SecondsToTimeString(positionInSeconds, TIME_FORMAT_HH_MM_SS)); + } + return resumeString; +} + +bool CPVRGUIActionsPlayback::CheckResumeRecording(const CFileItemPtr& item) const +{ + bool bPlayIt(true); + std::string resumeString(GetResumeLabel(*item)); + if (!resumeString.empty()) + { + CContextButtons choices; + choices.Add(CONTEXT_BUTTON_RESUME_ITEM, resumeString); + choices.Add(CONTEXT_BUTTON_PLAY_ITEM, 12021); // Play from beginning + int choice = CGUIDialogContextMenu::ShowAndGetChoice(choices); + if (choice > 0) + item->SetStartOffset(choice == CONTEXT_BUTTON_RESUME_ITEM ? STARTOFFSET_RESUME : 0); + else + bPlayIt = false; // context menu cancelled + } + return bPlayIt; +} + +bool CPVRGUIActionsPlayback::ResumePlayRecording(const CFileItemPtr& item, + bool bFallbackToPlay) const +{ + bool bCanResume = !GetResumeLabel(*item).empty(); + if (bCanResume) + { + item->SetStartOffset(STARTOFFSET_RESUME); + } + else + { + if (bFallbackToPlay) + item->SetStartOffset(0); + else + return false; + } + + return PlayRecording(item, false); +} + +void CPVRGUIActionsPlayback::CheckAndSwitchToFullscreen(bool bFullscreen) const +{ + CMediaSettings::GetInstance().SetMediaStartWindowed(!bFullscreen); + + if (bFullscreen) + { + CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, + CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()); + CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg); + } +} + +void CPVRGUIActionsPlayback::StartPlayback(CFileItem* item, + bool bFullscreen, + const CPVRStreamProperties* epgProps) const +{ + // Obtain dynamic playback url and properties from the respective pvr client + const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*item); + if (client) + { + CPVRStreamProperties props; + + if (item->IsPVRChannel()) + { + // If this was an EPG Tag to be played as live then PlayEpgTag() will create a channel + // fileitem instead and pass the epg tags props so we use those and skip the client call + if (epgProps) + props = *epgProps; + else + client->GetChannelStreamProperties(item->GetPVRChannelInfoTag(), props); + } + else if (item->IsPVRRecording()) + { + client->GetRecordingStreamProperties(item->GetPVRRecordingInfoTag(), props); + } + else if (item->IsEPG()) + { + if (epgProps) // we already have props from PlayEpgTag() + props = *epgProps; + else + client->GetEpgTagStreamProperties(item->GetEPGInfoTag(), props); + } + + if (props.size()) + { + const std::string url = props.GetStreamURL(); + if (!url.empty()) + item->SetDynPath(url); + + const std::string mime = props.GetStreamMimeType(); + if (!mime.empty()) + { + item->SetMimeType(mime); + item->SetContentLookup(false); + } + + for (const auto& prop : props) + item->SetProperty(prop.first, prop.second); + } + } + + CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY, 0, 0, static_cast<void*>(item)); + CheckAndSwitchToFullscreen(bFullscreen); +} + +bool CPVRGUIActionsPlayback::PlayRecording(const CFileItemPtr& item, bool bCheckResume) const +{ + const std::shared_ptr<CPVRRecording> recording(CPVRItem(item).GetRecording()); + if (!recording) + return false; + + if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRecording(recording)) + { + CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, + CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()); + CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg); + return true; + } + + if (!bCheckResume || CheckResumeRecording(item)) + { + CFileItem* itemToPlay = new CFileItem(recording); + itemToPlay->SetStartOffset(item->GetStartOffset()); + StartPlayback(itemToPlay, true); + } + return true; +} + +bool CPVRGUIActionsPlayback::PlayEpgTag(const CFileItemPtr& item) const +{ + const std::shared_ptr<CPVREpgInfoTag> epgTag(CPVRItem(item).GetEpgInfoTag()); + if (!epgTag) + return false; + + if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingEpgTag(epgTag)) + { + CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, + CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()); + CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg); + return true; + } + + // Obtain dynamic playback url and properties from the respective pvr client + const std::shared_ptr<CPVRClient> client = + CServiceBroker::GetPVRManager().GetClient(epgTag->ClientID()); + if (!client) + return false; + + CPVRStreamProperties props; + client->GetEpgTagStreamProperties(epgTag, props); + + CFileItem* itemToPlay = nullptr; + if (props.EPGPlaybackAsLive()) + { + const std::shared_ptr<CPVRChannelGroupMember> groupMember = + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(*item); + if (!groupMember) + return false; + + itemToPlay = new CFileItem(groupMember); + } + else + { + itemToPlay = new CFileItem(epgTag); + } + + StartPlayback(itemToPlay, true, &props); + return true; +} + +bool CPVRGUIActionsPlayback::SwitchToChannel(const CFileItemPtr& item, bool bCheckResume) const +{ + if (item->m_bIsFolder) + return false; + + std::shared_ptr<CPVRRecording> recording; + const std::shared_ptr<CPVRChannel> channel(CPVRItem(item).GetChannel()); + if (channel) + { + bool bSwitchToFullscreen = + CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingChannel(channel); + + if (!bSwitchToFullscreen) + { + recording = + CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(channel->GetEPGNow()); + bSwitchToFullscreen = + recording && + CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRecording(recording); + } + + if (bSwitchToFullscreen) + { + CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, + CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()); + CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg); + return true; + } + } + + ParentalCheckResult result = + channel ? CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalLock(channel) + : ParentalCheckResult::FAILED; + if (result == ParentalCheckResult::SUCCESS) + { + // switch to channel or if recording present, ask whether to switch or play recording... + if (!recording) + recording = + CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(channel->GetEPGNow()); + + if (recording) + { + bool bCancel(false); + bool bPlayRecording = CGUIDialogYesNo::ShowAndGetInput( + CVariant{19687}, // "Play recording" + CVariant{""}, CVariant{12021}, // "Play from beginning" + CVariant{recording->m_strTitle}, bCancel, CVariant{19000}, // "Switch to channel" + CVariant{19687}, // "Play recording" + 0); // no autoclose + if (bCancel) + return false; + + if (bPlayRecording) + { + const CFileItemPtr recordingItem(new CFileItem(recording)); + return PlayRecording(recordingItem, bCheckResume); + } + } + + bool bFullscreen; + switch (m_settings.GetIntValue(CSettings::SETTING_PVRPLAYBACK_SWITCHTOFULLSCREENCHANNELTYPES)) + { + case 0: // never + bFullscreen = false; + break; + case 1: // TV channels + bFullscreen = !channel->IsRadio(); + break; + case 2: // Radio channels + bFullscreen = channel->IsRadio(); + break; + case 3: // TV and radio channels + default: + bFullscreen = true; + break; + } + const std::shared_ptr<CPVRChannelGroupMember> groupMember = + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(*item); + if (!groupMember) + return false; + + StartPlayback(new CFileItem(groupMember), bFullscreen); + return true; + } + else if (result == ParentalCheckResult::FAILED) + { + const std::string channelName = + channel ? channel->ChannelName() : g_localizeStrings.Get(19029); // Channel + const std::string msg = StringUtils::Format( + g_localizeStrings.Get(19035), + channelName); // CHANNELNAME could not be played. Check the log for details. + + CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(19166), + msg); // PVR information + } + + return false; +} + +bool CPVRGUIActionsPlayback::SwitchToChannel(PlaybackType type) const +{ + std::shared_ptr<CPVRChannelGroupMember> groupMember; + bool bIsRadio(false); + + // check if the desired PlaybackType is already playing, + // and if not, try to grab the last played channel of this type + switch (type) + { + case PlaybackTypeRadio: + { + if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRadio()) + return true; + + const std::shared_ptr<CPVRChannelGroup> allGroup = + CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllRadio(); + if (allGroup) + groupMember = allGroup->GetLastPlayedChannelGroupMember(); + + bIsRadio = true; + break; + } + case PlaybackTypeTV: + { + if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingTV()) + return true; + + const std::shared_ptr<CPVRChannelGroup> allGroup = + CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllTV(); + if (allGroup) + groupMember = allGroup->GetLastPlayedChannelGroupMember(); + + break; + } + default: + if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlaying()) + return true; + + groupMember = + CServiceBroker::GetPVRManager().ChannelGroups()->GetLastPlayedChannelGroupMember(); + break; + } + + // if we have a last played channel, start playback + if (groupMember) + { + return SwitchToChannel(std::make_shared<CFileItem>(groupMember), true); + } + else + { + // if we don't, find the active channel group of the demanded type and play it's first channel + const std::shared_ptr<CPVRChannelGroup> channelGroup = + CServiceBroker::GetPVRManager().PlaybackState()->GetActiveChannelGroup(bIsRadio); + if (channelGroup) + { + // try to start playback of first channel in this group + const std::vector<std::shared_ptr<CPVRChannelGroupMember>> groupMembers = + channelGroup->GetMembers(); + if (!groupMembers.empty()) + { + return SwitchToChannel(std::make_shared<CFileItem>(*groupMembers.begin()), true); + } + } + } + + CLog::LogF(LOGERROR, + "Could not determine {} channel to playback. No last played channel found, and " + "first channel of active group could also not be determined.", + bIsRadio ? "Radio" : "TV"); + + CGUIDialogKaiToast::QueueNotification( + CGUIDialogKaiToast::Error, + g_localizeStrings.Get(19166), // PVR information + StringUtils::Format( + g_localizeStrings.Get(19035), + g_localizeStrings.Get( + bIsRadio ? 19021 + : 19020))); // Radio/TV could not be played. Check the log for details. + return false; +} + +bool CPVRGUIActionsPlayback::PlayChannelOnStartup() const +{ + int iAction = m_settings.GetIntValue(CSettings::SETTING_LOOKANDFEEL_STARTUPACTION); + if (iAction != STARTUP_ACTION_PLAY_TV && iAction != STARTUP_ACTION_PLAY_RADIO) + return false; + + bool playRadio = (iAction == STARTUP_ACTION_PLAY_RADIO); + + // get the last played channel or fallback to first channel of all channels group + std::shared_ptr<CPVRChannelGroupMember> groupMember = + CServiceBroker::GetPVRManager().PlaybackState()->GetLastPlayedChannelGroupMember(playRadio); + + if (!groupMember) + { + const std::shared_ptr<CPVRChannelGroup> group = + CServiceBroker::GetPVRManager().ChannelGroups()->Get(playRadio)->GetGroupAll(); + auto channels = group->GetMembers(); + if (channels.empty()) + return false; + + groupMember = channels.front(); + if (!groupMember) + return false; + } + + CLog::Log(LOGINFO, "PVR is starting playback of channel '{}'", + groupMember->Channel()->ChannelName()); + return SwitchToChannel(std::make_shared<CFileItem>(groupMember), true); +} + +bool CPVRGUIActionsPlayback::PlayMedia(const CFileItemPtr& item) const +{ + CFileItemPtr pvrItem(item); + if (URIUtils::IsPVRChannel(item->GetPath()) && !item->HasPVRChannelInfoTag()) + { + const std::shared_ptr<CPVRChannelGroupMember> groupMember = + CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelGroupMemberByPath( + item->GetPath()); + if (groupMember) + pvrItem = std::make_shared<CFileItem>(groupMember); + } + else if (URIUtils::IsPVRRecording(item->GetPath()) && !item->HasPVRRecordingInfoTag()) + pvrItem = std::make_shared<CFileItem>( + CServiceBroker::GetPVRManager().Recordings()->GetByPath(item->GetPath())); + + bool bCheckResume = true; + if (item->HasProperty("check_resume")) + bCheckResume = item->GetProperty("check_resume").asBoolean(); + + if (pvrItem && pvrItem->HasPVRChannelInfoTag()) + { + return SwitchToChannel(pvrItem, bCheckResume); + } + else if (pvrItem && pvrItem->HasPVRRecordingInfoTag()) + { + return PlayRecording(pvrItem, bCheckResume); + } + + return false; +} + +void CPVRGUIActionsPlayback::SeekForward() +{ + time_t playbackStartTime = CServiceBroker::GetDataCacheCore().GetStartTime(); + if (playbackStartTime > 0) + { + const std::shared_ptr<CPVRChannel> playingChannel = + CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel(); + if (playingChannel) + { + time_t nextTime = 0; + std::shared_ptr<CPVREpgInfoTag> next = playingChannel->GetEPGNext(); + if (next) + { + next->StartAsUTC().GetAsTime(nextTime); + } + else + { + // if there is no next event, jump to end of currently playing event + next = playingChannel->GetEPGNow(); + if (next) + next->EndAsUTC().GetAsTime(nextTime); + } + + int64_t seekTime = 0; + if (nextTime != 0) + { + seekTime = (nextTime - playbackStartTime) * 1000; + } + else + { + // no epg; jump to end of buffer + seekTime = CServiceBroker::GetDataCacheCore().GetMaxTime(); + } + CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_SEEK_TIME, seekTime); + } + } +} + +void CPVRGUIActionsPlayback::SeekBackward(unsigned int iThreshold) +{ + time_t playbackStartTime = CServiceBroker::GetDataCacheCore().GetStartTime(); + if (playbackStartTime > 0) + { + const std::shared_ptr<CPVRChannel> playingChannel = + CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel(); + if (playingChannel) + { + time_t prevTime = 0; + std::shared_ptr<CPVREpgInfoTag> prev = playingChannel->GetEPGNow(); + if (prev) + { + prev->StartAsUTC().GetAsTime(prevTime); + + // if playback time of current event is above threshold jump to start of current event + int64_t playTime = CServiceBroker::GetDataCacheCore().GetPlayTime() / 1000; + if ((playbackStartTime + playTime - prevTime) <= iThreshold) + { + // jump to start of previous event + prevTime = 0; + prev = playingChannel->GetEPGPrevious(); + if (prev) + prev->StartAsUTC().GetAsTime(prevTime); + } + } + + int64_t seekTime = 0; + if (prevTime != 0) + { + seekTime = (prevTime - playbackStartTime) * 1000; + } + else + { + // no epg; jump to begin of buffer + seekTime = CServiceBroker::GetDataCacheCore().GetMinTime(); + } + CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_SEEK_TIME, seekTime); + } + } +} diff --git a/xbmc/pvr/guilib/PVRGUIActionsPlayback.h b/xbmc/pvr/guilib/PVRGUIActionsPlayback.h new file mode 100644 index 0000000000..d9aff681a2 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsPlayback.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "pvr/IPVRComponent.h" +#include "pvr/settings/PVRSettings.h" + +#include <memory> +#include <string> + +class CFileItem; + +namespace PVR +{ +enum PlaybackType +{ + PlaybackTypeAny = 0, + PlaybackTypeTV, + PlaybackTypeRadio +}; + +class CPVRStreamProperties; + +class CPVRGUIActionsPlayback : public IPVRComponent +{ +public: + CPVRGUIActionsPlayback(); + virtual ~CPVRGUIActionsPlayback() = default; + + /*! + * @brief Get a localized resume play label, if the given item can be resumed. + * @param item containing a recording or an epg tag. + * @return the localized resume play label that can be used for instance as context menu item + * label or an empty string if resume is not possible. + */ + std::string GetResumeLabel(const CFileItem& item) const; + + /*! + * @brief Resume a previously not completely played recording. + * @param item containing a recording or an epg tag. + * @param bFallbackToPlay controls whether playback of the recording should be started at the + * beginning ig no resume data are available. + * @return true on success, false otherwise. + */ + bool ResumePlayRecording(const std::shared_ptr<CFileItem>& item, bool bFallbackToPlay) const; + + /*! + * @brief Play recording. + * @param item containing a recording or an epg tag. + * @param bCheckResume controls resume check. + * @return true on success, false otherwise. + */ + bool PlayRecording(const std::shared_ptr<CFileItem>& item, bool bCheckResume) const; + + /*! + * @brief Play EPG tag. + * @param item containing an epg tag. + * @return true on success, false otherwise. + */ + bool PlayEpgTag(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Switch channel. + * @param item containing a channel or an epg tag. + * @param bCheckResume controls resume check in case a recording for the current epg event is + * present. + * @return true on success, false otherwise. + */ + bool SwitchToChannel(const std::shared_ptr<CFileItem>& item, bool bCheckResume) const; + + /*! + * @brief Playback the given file item. + * @param item containing a channel or a recording. + * @return True if the item could be played, false otherwise. + */ + bool PlayMedia(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Start playback of the last played channel, and if there is none, play first channel in + * the current channelgroup. + * @param type The type of playback to be started (any, radio, tv). See PlaybackType enum + * @return True if playback was started, false otherwise. + */ + bool SwitchToChannel(PlaybackType type) const; + + /*! + * @brief Plays the last played channel or the first channel of TV or Radio on startup. + * @return True if playback was started, false otherwise. + */ + bool PlayChannelOnStartup() const; + + /*! + * @brief Seek to the start of the next epg event in timeshift buffer, relative to the currently + * playing event. If there is no next event, seek to the end of the currently playing event (to + * the 'live' position). + */ + void SeekForward(); + + /*! + * @brief Seek to the start of the previous epg event in timeshift buffer, relative to the + * currently playing event or if there is no previous event or if playback time is greater than + * given threshold, seek to the start of the playing event. + * @param iThreshold the value in seconds to trigger seek to start of current event instead of + * start of previous event. + */ + void SeekBackward(unsigned int iThreshold); + +private: + CPVRGUIActionsPlayback(const CPVRGUIActionsPlayback&) = delete; + CPVRGUIActionsPlayback const& operator=(CPVRGUIActionsPlayback const&) = delete; + + /*! + * @brief Check whether resume play is possible for a given item, display "resume from ..."/"play + * from start" context menu in case. + * @param item containing a recording or an epg tag. + * @return true, to play/resume the item, false otherwise. + */ + bool CheckResumeRecording(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Check "play minimized" settings value and switch to fullscreen if not set. + * @param bFullscreen switch to fullscreen or set windowed playback. + */ + void CheckAndSwitchToFullscreen(bool bFullscreen) const; + + /*! + * @brief Start playback of the given item. + * @param bFullscreen start playback fullscreen or not. + * @param epgProps properties to be used instead of calling to the client if supplied. + * @param item containing a channel or a recording. + */ + void StartPlayback(CFileItem* item, + bool bFullscreen, + const CPVRStreamProperties* epgProps = nullptr) const; + + CPVRSettings m_settings; +}; + +namespace GUI +{ +// pretty scope and name +using Playback = CPVRGUIActionsPlayback; +} // namespace GUI + +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp b/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp new file mode 100644 index 0000000000..101bfa7a6a --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIActionsPowerManagement.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "guilib/LocalizeStrings.h" +#include "messaging/helpers/DialogHelper.h" +#include "network/Network.h" +#include "pvr/PVRManager.h" +#include "pvr/addons/PVRClient.h" +#include "pvr/timers/PVRTimerInfoTag.h" +#include "pvr/timers/PVRTimers.h" +#include "settings/Settings.h" +#include "utils/StringUtils.h" +#include "utils/Variant.h" + +#include <memory> +#include <string> +#include <vector> + +using namespace PVR; +using namespace KODI::MESSAGING; + +CPVRGUIActionsPowerManagement::CPVRGUIActionsPowerManagement() + : m_settings({CSettings::SETTING_PVRPOWERMANAGEMENT_DAILYWAKEUPTIME, + CSettings::SETTING_PVRPOWERMANAGEMENT_BACKENDIDLETIME}) +{ +} + +bool CPVRGUIActionsPowerManagement::CanSystemPowerdown(bool bAskUser /*= true*/) const +{ + bool bReturn(true); + if (CServiceBroker::GetPVRManager().IsStarted()) + { + std::shared_ptr<CPVRTimerInfoTag> cause; + if (!AllLocalBackendsIdle(cause)) + { + if (bAskUser) + { + std::string text; + + if (cause) + { + if (cause->IsRecording()) + { + text = StringUtils::Format( + g_localizeStrings.Get(19691), // "PVR is currently recording...." + cause->Title(), cause->ChannelName()); + } + else + { + // Next event is due to a local recording or reminder. + const CDateTime now(CDateTime::GetUTCDateTime()); + const CDateTime start(cause->StartAsUTC()); + const CDateTimeSpan prestart(0, 0, cause->MarginStart(), 0); + + CDateTimeSpan diff(start - now); + diff -= prestart; + int mins = diff.GetSecondsTotal() / 60; + + std::string dueStr; + if (mins > 1) + { + // "%d minutes" + dueStr = StringUtils::Format(g_localizeStrings.Get(19694), mins); + } + else + { + // "about a minute" + dueStr = g_localizeStrings.Get(19695); + } + + text = StringUtils::Format( + cause->IsReminder() + ? g_localizeStrings.Get(19690) // "PVR has scheduled a reminder...." + : g_localizeStrings.Get(19692), // "PVR will start recording...." + cause->Title(), cause->ChannelName(), dueStr); + } + } + else + { + // Next event is due to automatic daily wakeup of PVR. + const CDateTime now(CDateTime::GetUTCDateTime()); + + CDateTime dailywakeuptime; + dailywakeuptime.SetFromDBTime( + m_settings.GetStringValue(CSettings::SETTING_PVRPOWERMANAGEMENT_DAILYWAKEUPTIME)); + dailywakeuptime = dailywakeuptime.GetAsUTCDateTime(); + + const CDateTimeSpan diff(dailywakeuptime - now); + int mins = diff.GetSecondsTotal() / 60; + + std::string dueStr; + if (mins > 1) + { + // "%d minutes" + dueStr = StringUtils::Format(g_localizeStrings.Get(19694), mins); + } + else + { + // "about a minute" + dueStr = g_localizeStrings.Get(19695); + } + + text = StringUtils::Format(g_localizeStrings.Get(19693), // "Daily wakeup is due in...." + dueStr); + } + + // Inform user about PVR being busy. Ask if user wants to powerdown anyway. + bReturn = HELPERS::ShowYesNoDialogText(CVariant{19685}, // "Confirm shutdown" + CVariant{text}, CVariant{222}, // "Shutdown anyway", + CVariant{19696}, // "Cancel" + 10000) // timeout value before closing + == HELPERS::DialogResponse::CHOICE_YES; + } + else + bReturn = false; // do not powerdown (busy, but no user interaction requested). + } + } + return bReturn; +} + +bool CPVRGUIActionsPowerManagement::AllLocalBackendsIdle( + std::shared_ptr<CPVRTimerInfoTag>& causingEvent) const +{ + // active recording on local backend? + const std::vector<std::shared_ptr<CPVRTimerInfoTag>> activeRecordings = + CServiceBroker::GetPVRManager().Timers()->GetActiveRecordings(); + for (const auto& timer : activeRecordings) + { + if (EventOccursOnLocalBackend(std::make_shared<CFileItem>(timer))) + { + causingEvent = timer; + return false; + } + } + + // soon recording on local backend? + if (IsNextEventWithinBackendIdleTime()) + { + const std::shared_ptr<CPVRTimerInfoTag> timer = + CServiceBroker::GetPVRManager().Timers()->GetNextActiveTimer(false); + if (!timer) + { + // Next event is due to automatic daily wakeup of PVR! + causingEvent.reset(); + return false; + } + + if (EventOccursOnLocalBackend(std::make_shared<CFileItem>(timer))) + { + causingEvent = timer; + return false; + } + } + return true; +} + +bool CPVRGUIActionsPowerManagement::EventOccursOnLocalBackend( + const std::shared_ptr<CFileItem>& item) const +{ + if (item && item->HasPVRTimerInfoTag()) + { + const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*item); + if (client) + { + const std::string hostname = client->GetBackendHostname(); + if (!hostname.empty() && CServiceBroker::GetNetwork().IsLocalHost(hostname)) + return true; + } + } + return false; +} + +bool CPVRGUIActionsPowerManagement::IsNextEventWithinBackendIdleTime() const +{ + // timers going off soon? + const CDateTime now(CDateTime::GetUTCDateTime()); + const CDateTimeSpan idle( + 0, 0, m_settings.GetIntValue(CSettings::SETTING_PVRPOWERMANAGEMENT_BACKENDIDLETIME), 0); + const CDateTime next(CServiceBroker::GetPVRManager().Timers()->GetNextEventTime()); + const CDateTimeSpan delta(next - now); + + return (delta <= idle); +} diff --git a/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.h b/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.h new file mode 100644 index 0000000000..e8e1548b2c --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsPowerManagement.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "pvr/IPVRComponent.h" +#include "pvr/settings/PVRSettings.h" + +#include <memory> + +class CFileItem; + +namespace PVR +{ +class CPVRTimerInfoTag; + +class CPVRGUIActionsPowerManagement : public IPVRComponent +{ +public: + CPVRGUIActionsPowerManagement(); + virtual ~CPVRGUIActionsPowerManagement() = default; + + /*! + * @brief Check whether the system Kodi is running on can be powered down + * (shutdown/reboot/suspend/hibernate) without stopping any active recordings and/or without + * preventing the start of recordings scheduled for now + pvrpowermanagement.backendidletime. + * @param bAskUser True to informs user in case of potential data loss. User can decide to allow + * powerdown anyway. False to not to ask user and to not confirm power down. + * @return True if system can be safely powered down, false otherwise. + */ + bool CanSystemPowerdown(bool bAskUser = true) const; + +private: + CPVRGUIActionsPowerManagement(const CPVRGUIActionsPowerManagement&) = delete; + CPVRGUIActionsPowerManagement const& operator=(CPVRGUIActionsPowerManagement const&) = delete; + + bool AllLocalBackendsIdle(std::shared_ptr<CPVRTimerInfoTag>& causingEvent) const; + bool EventOccursOnLocalBackend(const std::shared_ptr<CFileItem>& item) const; + bool IsNextEventWithinBackendIdleTime() const; + + CPVRSettings m_settings; +}; + +namespace GUI +{ +// pretty scope and name +using PowerManagement = CPVRGUIActionsPowerManagement; +} // namespace GUI + +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsRecordings.cpp b/xbmc/pvr/guilib/PVRGUIActionsRecordings.cpp new file mode 100644 index 0000000000..90d804f8c8 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsRecordings.cpp @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIActionsRecordings.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "Util.h" +#include "dialogs/GUIDialogBusy.h" +#include "dialogs/GUIDialogYesNo.h" +#include "filesystem/IDirectory.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/WindowIDs.h" +#include "messaging/helpers/DialogOKHelper.h" +#include "pvr/PVRItem.h" +#include "pvr/PVRManager.h" +#include "pvr/addons/PVRClient.h" +#include "pvr/addons/PVRClients.h" +#include "pvr/dialogs/GUIDialogPVRRecordingInfo.h" +#include "pvr/dialogs/GUIDialogPVRRecordingSettings.h" +#include "pvr/recordings/PVRRecording.h" +#include "settings/Settings.h" +#include "threads/IRunnable.h" +#include "utils/Variant.h" +#include "utils/log.h" + +#include <memory> +#include <numeric> +#include <string> + +using namespace PVR; +using namespace KODI::MESSAGING; + +namespace +{ +class AsyncRecordingAction : private IRunnable +{ +public: + bool Execute(const CFileItemPtr& item); + +protected: + AsyncRecordingAction() = default; + +private: + // IRunnable implementation + void Run() override; + + // the worker function + virtual bool DoRun(const CFileItemPtr& item) = 0; + + CFileItemPtr m_item; + bool m_bSuccess = false; +}; + +bool AsyncRecordingAction::Execute(const CFileItemPtr& item) +{ + m_item = item; + CGUIDialogBusy::Wait(this, 100, false); + return m_bSuccess; +} + +void AsyncRecordingAction::Run() +{ + m_bSuccess = DoRun(m_item); + + if (m_bSuccess) + CServiceBroker::GetPVRManager().TriggerRecordingsUpdate(); +} + +class AsyncRenameRecording : public AsyncRecordingAction +{ +public: + explicit AsyncRenameRecording(const std::string& strNewName) : m_strNewName(strNewName) {} + +private: + bool DoRun(const std::shared_ptr<CFileItem>& item) override + { + if (item->IsUsablePVRRecording()) + { + return item->GetPVRRecordingInfoTag()->Rename(m_strNewName); + } + else + { + CLog::LogF(LOGERROR, "Cannot rename item '{}': no valid recording tag", item->GetPath()); + return false; + } + } + std::string m_strNewName; +}; + +class AsyncDeleteRecording : public AsyncRecordingAction +{ +public: + explicit AsyncDeleteRecording(bool bWatchedOnly = false) : m_bWatchedOnly(bWatchedOnly) {} + +private: + bool DoRun(const std::shared_ptr<CFileItem>& item) override + { + CFileItemList items; + if (item->m_bIsFolder) + { + CUtil::GetRecursiveListing(item->GetPath(), items, "", XFILE::DIR_FLAG_NO_FILE_INFO); + } + else + { + items.Add(item); + } + + return std::accumulate( + items.cbegin(), items.cend(), true, [this](bool success, const auto& itemToDelete) { + return (itemToDelete->IsPVRRecording() && + (!m_bWatchedOnly || itemToDelete->GetPVRRecordingInfoTag()->GetPlayCount() > 0) && + !itemToDelete->GetPVRRecordingInfoTag()->Delete()) + ? false + : success; + }); + } + bool m_bWatchedOnly = false; +}; + +class AsyncEmptyRecordingsTrash : public AsyncRecordingAction +{ +private: + bool DoRun(const std::shared_ptr<CFileItem>& item) override + { + return CServiceBroker::GetPVRManager().Clients()->DeleteAllRecordingsFromTrash() == + PVR_ERROR_NO_ERROR; + } +}; + +class AsyncUndeleteRecording : public AsyncRecordingAction +{ +private: + bool DoRun(const std::shared_ptr<CFileItem>& item) override + { + if (item->IsDeletedPVRRecording()) + { + return item->GetPVRRecordingInfoTag()->Undelete(); + } + else + { + CLog::LogF(LOGERROR, "Cannot undelete item '{}': no valid recording tag", item->GetPath()); + return false; + } + } +}; + +class AsyncSetRecordingPlayCount : public AsyncRecordingAction +{ +private: + bool DoRun(const CFileItemPtr& item) override + { + const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*item); + if (client) + { + const std::shared_ptr<CPVRRecording> recording = item->GetPVRRecordingInfoTag(); + return client->SetRecordingPlayCount(*recording, recording->GetLocalPlayCount()) == + PVR_ERROR_NO_ERROR; + } + return false; + } +}; + +class AsyncSetRecordingLifetime : public AsyncRecordingAction +{ +private: + bool DoRun(const CFileItemPtr& item) override + { + const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*item); + if (client) + return client->SetRecordingLifetime(*item->GetPVRRecordingInfoTag()) == PVR_ERROR_NO_ERROR; + return false; + } +}; + +} // unnamed namespace + +bool CPVRGUIActionsRecordings::ShowRecordingInfo(const CFileItemPtr& item) const +{ + if (!item->IsPVRRecording()) + { + CLog::LogF(LOGERROR, "No recording!"); + return false; + } + + CGUIDialogPVRRecordingInfo* pDlgInfo = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRRecordingInfo>( + WINDOW_DIALOG_PVR_RECORDING_INFO); + if (!pDlgInfo) + { + CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PVR_RECORDING_INFO!"); + return false; + } + + pDlgInfo->SetRecording(item.get()); + pDlgInfo->Open(); + return true; +} + +bool CPVRGUIActionsRecordings::EditRecording(const CFileItemPtr& item) const +{ + const std::shared_ptr<CPVRRecording> recording = CPVRItem(item).GetRecording(); + if (!recording) + { + CLog::LogF(LOGERROR, "No recording!"); + return false; + } + + std::shared_ptr<CPVRRecording> origRecording(new CPVRRecording); + origRecording->Update(*recording, + *CServiceBroker::GetPVRManager().GetClient(recording->m_iClientId)); + + if (!ShowRecordingSettings(recording)) + return false; + + if (origRecording->m_strTitle != recording->m_strTitle) + { + if (!AsyncRenameRecording(recording->m_strTitle).Execute(item)) + CLog::LogF(LOGERROR, "Renaming recording failed!"); + } + + if (origRecording->GetLocalPlayCount() != recording->GetLocalPlayCount()) + { + if (!AsyncSetRecordingPlayCount().Execute(item)) + CLog::LogF(LOGERROR, "Setting recording playcount failed!"); + } + + if (origRecording->m_iLifetime != recording->m_iLifetime) + { + if (!AsyncSetRecordingLifetime().Execute(item)) + CLog::LogF(LOGERROR, "Setting recording lifetime failed!"); + } + + return true; +} + +bool CPVRGUIActionsRecordings::CanEditRecording(const CFileItem& item) const +{ + return CGUIDialogPVRRecordingSettings::CanEditRecording(item); +} + +bool CPVRGUIActionsRecordings::DeleteRecording(const CFileItemPtr& item) const +{ + if ((!item->IsPVRRecording() && !item->m_bIsFolder) || item->IsParentFolder()) + return false; + + if (!ConfirmDeleteRecording(item)) + return false; + + if (!AsyncDeleteRecording().Execute(item)) + { + HELPERS::ShowOKDialogText( + CVariant{257}, + CVariant{ + 19111}); // "Error", "PVR backend error. Check the log for more information about this message." + return false; + } + + return true; +} + +bool CPVRGUIActionsRecordings::ConfirmDeleteRecording(const CFileItemPtr& item) const +{ + return CGUIDialogYesNo::ShowAndGetInput( + CVariant{122}, // "Confirm delete" + item->m_bIsFolder + ? CVariant{19113} // "Delete all recordings in this folder?" + : item->GetPVRRecordingInfoTag()->IsDeleted() + ? CVariant{19294} + // "Remove this deleted recording from trash? This operation cannot be reverted." + : CVariant{19112}, // "Delete this recording?" + CVariant{""}, CVariant{item->GetLabel()}); +} + +bool CPVRGUIActionsRecordings::DeleteWatchedRecordings(const std::shared_ptr<CFileItem>& item) const +{ + if (!item->m_bIsFolder || item->IsParentFolder()) + return false; + + if (!ConfirmDeleteWatchedRecordings(item)) + return false; + + if (!AsyncDeleteRecording(true).Execute(item)) + { + HELPERS::ShowOKDialogText( + CVariant{257}, + CVariant{ + 19111}); // "Error", "PVR backend error. Check the log for more information about this message." + return false; + } + + return true; +} + +bool CPVRGUIActionsRecordings::ConfirmDeleteWatchedRecordings( + const std::shared_ptr<CFileItem>& item) const +{ + return CGUIDialogYesNo::ShowAndGetInput( + CVariant{122}, // "Confirm delete" + CVariant{19328}, // "Delete all watched recordings in this folder?" + CVariant{""}, CVariant{item->GetLabel()}); +} + +bool CPVRGUIActionsRecordings::DeleteAllRecordingsFromTrash() const +{ + if (!ConfirmDeleteAllRecordingsFromTrash()) + return false; + + if (!AsyncEmptyRecordingsTrash().Execute(CFileItemPtr())) + return false; + + return true; +} + +bool CPVRGUIActionsRecordings::ConfirmDeleteAllRecordingsFromTrash() const +{ + return CGUIDialogYesNo::ShowAndGetInput( + CVariant{19292}, // "Delete all permanently" + CVariant{ + 19293}); // "Remove all deleted recordings from trash? This operation cannot be reverted." +} + +bool CPVRGUIActionsRecordings::UndeleteRecording(const CFileItemPtr& item) const +{ + if (!item->IsDeletedPVRRecording()) + return false; + + if (!AsyncUndeleteRecording().Execute(item)) + { + HELPERS::ShowOKDialogText( + CVariant{257}, + CVariant{ + 19111}); // "Error", "PVR backend error. Check the log for more information about this message." + return false; + } + + return true; +} + +bool CPVRGUIActionsRecordings::ShowRecordingSettings( + const std::shared_ptr<CPVRRecording>& recording) const +{ + CGUIDialogPVRRecordingSettings* pDlgInfo = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRRecordingSettings>( + WINDOW_DIALOG_PVR_RECORDING_SETTING); + if (!pDlgInfo) + { + CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PVR_RECORDING_SETTING!"); + return false; + } + + pDlgInfo->SetRecording(recording); + pDlgInfo->Open(); + + return pDlgInfo->IsConfirmed(); +} diff --git a/xbmc/pvr/guilib/PVRGUIActionsRecordings.h b/xbmc/pvr/guilib/PVRGUIActionsRecordings.h new file mode 100644 index 0000000000..fef7ef839a --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsRecordings.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "pvr/IPVRComponent.h" + +#include <memory> + +class CFileItem; + +namespace PVR +{ +class CPVRRecording; + +class CPVRGUIActionsRecordings : public IPVRComponent +{ +public: + CPVRGUIActionsRecordings() = default; + virtual ~CPVRGUIActionsRecordings() = default; + + /*! + * @brief Open a dialog with information for a given recording. + * @param item containing a recording. + * @return true on success, false otherwise. + */ + bool ShowRecordingInfo(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Open the recording settings dialog to edit a recording. + * @param item containing the recording to edit. + * @return true on success, false otherwise. + */ + bool EditRecording(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Check if any recording settings can be edited. + * @param item containing the recording to edit. + * @return true on success, false otherwise. + */ + bool CanEditRecording(const CFileItem& item) const; + + /*! + * @brief Delete a recording, always showing a confirmation dialog. + * @param item containing a recording to delete. + * @return true, if the recording was deleted successfully, false otherwise. + */ + bool DeleteRecording(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Delete all watched recordings contained in the given folder, always showing a + * confirmation dialog. + * @param item containing a recording folder containing the items to delete. + * @return true, if the recordings were deleted successfully, false otherwise. + */ + bool DeleteWatchedRecordings(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Delete all recordings from trash, always showing a confirmation dialog. + * @return true, if the recordings were permanently deleted successfully, false otherwise. + */ + bool DeleteAllRecordingsFromTrash() const; + + /*! + * @brief Undelete a recording. + * @param item containing a recording to undelete. + * @return true, if the recording was undeleted successfully, false otherwise. + */ + bool UndeleteRecording(const std::shared_ptr<CFileItem>& item) const; + +private: + CPVRGUIActionsRecordings(const CPVRGUIActionsRecordings&) = delete; + CPVRGUIActionsRecordings const& operator=(CPVRGUIActionsRecordings const&) = delete; + + /*! + * @brief Open a dialog to confirm to delete a recording. + * @param item the recording to delete. + * @return true, to proceed with delete, false otherwise. + */ + bool ConfirmDeleteRecording(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Open a dialog to confirm delete all watched recordings contained in the given folder. + * @param item containing a recording folder containing the items to delete. + * @return true, to proceed with delete, false otherwise. + */ + bool ConfirmDeleteWatchedRecordings(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Open a dialog to confirm to permanently remove all deleted recordings. + * @return true, to proceed with delete, false otherwise. + */ + bool ConfirmDeleteAllRecordingsFromTrash() const; + + /*! + * @brief Open the recording settings dialog. + * @param recording containing the recording the settings shall be displayed for. + * @return true, if the dialog was ended successfully, false otherwise. + */ + bool ShowRecordingSettings(const std::shared_ptr<CPVRRecording>& recording) const; +}; + +namespace GUI +{ +// pretty scope and name +using Recordings = CPVRGUIActionsRecordings; +} // namespace GUI + +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsTimers.cpp b/xbmc/pvr/guilib/PVRGUIActionsTimers.cpp new file mode 100644 index 0000000000..d78897cd04 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsTimers.cpp @@ -0,0 +1,1010 @@ +/* + * Copyright (C) 2016-2022 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIActionsTimers.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "dialogs/GUIDialogProgress.h" +#include "dialogs/GUIDialogSelect.h" +#include "dialogs/GUIDialogYesNo.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/LocalizeStrings.h" +#include "guilib/WindowIDs.h" +#include "messaging/helpers/DialogHelper.h" +#include "messaging/helpers/DialogOKHelper.h" +#include "pvr/PVREventLogJob.h" +#include "pvr/PVRItem.h" +#include "pvr/PVRManager.h" +#include "pvr/PVRPlaybackState.h" +#include "pvr/addons/PVRClient.h" +#include "pvr/channels/PVRChannel.h" +#include "pvr/channels/PVRChannelGroupMember.h" +#include "pvr/dialogs/GUIDialogPVRTimerSettings.h" +#include "pvr/epg/EpgInfoTag.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsParentalControl.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" +#include "pvr/recordings/PVRRecording.h" +#include "pvr/timers/PVRTimerInfoTag.h" +#include "pvr/timers/PVRTimers.h" +#include "settings/Settings.h" +#include "utils/StringUtils.h" +#include "utils/SystemInfo.h" +#include "utils/Variant.h" +#include "utils/log.h" + +#include <algorithm> +#include <map> +#include <memory> +#include <string> +#include <thread> +#include <utility> + +using namespace PVR; +using namespace KODI::MESSAGING; + +CPVRGUIActionsTimers::CPVRGUIActionsTimers() + : m_settings({CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME, + CSettings::SETTING_PVRRECORD_INSTANTRECORDACTION, + CSettings::SETTING_PVRREMINDERS_AUTOCLOSEDELAY, + CSettings::SETTING_PVRREMINDERS_AUTORECORD, + CSettings::SETTING_PVRREMINDERS_AUTOSWITCH}) +{ +} + +bool CPVRGUIActionsTimers::ShowTimerSettings(const std::shared_ptr<CPVRTimerInfoTag>& timer) const +{ + CGUIDialogPVRTimerSettings* pDlgInfo = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRTimerSettings>( + WINDOW_DIALOG_PVR_TIMER_SETTING); + if (!pDlgInfo) + { + CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_PVR_TIMER_SETTING!"); + return false; + } + + pDlgInfo->SetTimer(timer); + pDlgInfo->Open(); + + return pDlgInfo->IsConfirmed(); +} + +bool CPVRGUIActionsTimers::AddReminder(const std::shared_ptr<CFileItem>& item) const +{ + const std::shared_ptr<CPVREpgInfoTag> epgTag = CPVRItem(item).GetEpgInfoTag(); + if (!epgTag) + { + CLog::LogF(LOGERROR, "No epg tag!"); + return false; + } + + if (CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epgTag)) + { + HELPERS::ShowOKDialogText(CVariant{19033}, // "Information" + CVariant{19034}); // "There is already a timer set for this event" + return false; + } + + const std::shared_ptr<CPVRTimerInfoTag> newTimer = + CPVRTimerInfoTag::CreateReminderFromEpg(epgTag); + if (!newTimer) + { + HELPERS::ShowOKDialogText(CVariant{19033}, // "Information" + CVariant{19094}); // Timer creation failed. Unsupported timer type. + return false; + } + + return AddTimer(newTimer); +} + +bool CPVRGUIActionsTimers::AddTimer(bool bRadio) const +{ + const std::shared_ptr<CPVRTimerInfoTag> newTimer(new CPVRTimerInfoTag(bRadio)); + if (ShowTimerSettings(newTimer)) + { + return AddTimer(newTimer); + } + return false; +} + +bool CPVRGUIActionsTimers::AddTimer(const CFileItemPtr& item, bool bShowTimerSettings) const +{ + return AddTimer(item, false, bShowTimerSettings, false); +} + +bool CPVRGUIActionsTimers::AddTimerRule(const std::shared_ptr<CFileItem>& item, + bool bShowTimerSettings, + bool bFallbackToOneShotTimer) const +{ + return AddTimer(item, true, bShowTimerSettings, bFallbackToOneShotTimer); +} + +bool CPVRGUIActionsTimers::AddTimer(const std::shared_ptr<CFileItem>& item, + bool bCreateRule, + bool bShowTimerSettings, + bool bFallbackToOneShotTimer) const +{ + const std::shared_ptr<CPVRChannel> channel(CPVRItem(item).GetChannel()); + if (!channel) + { + CLog::LogF(LOGERROR, "No channel!"); + return false; + } + + if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalLock(channel) != + ParentalCheckResult::SUCCESS) + return false; + + std::shared_ptr<CPVREpgInfoTag> epgTag = CPVRItem(item).GetEpgInfoTag(); + if (epgTag) + { + if (epgTag->IsGapTag()) + epgTag.reset(); // for gap tags, we can only create instant timers + } + else if (bCreateRule) + { + CLog::LogF(LOGERROR, "No epg tag!"); + return false; + } + + std::shared_ptr<CPVRTimerInfoTag> timer( + bCreateRule || !epgTag ? nullptr + : CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epgTag)); + std::shared_ptr<CPVRTimerInfoTag> rule( + bCreateRule ? CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer) : nullptr); + if (timer || rule) + { + HELPERS::ShowOKDialogText( + CVariant{19033}, + CVariant{19034}); // "Information", "There is already a timer set for this event" + return false; + } + + std::shared_ptr<CPVRTimerInfoTag> newTimer( + epgTag ? CPVRTimerInfoTag::CreateFromEpg(epgTag, bCreateRule) + : CPVRTimerInfoTag::CreateInstantTimerTag(channel)); + if (!newTimer) + { + if (bCreateRule && bFallbackToOneShotTimer) + newTimer = CPVRTimerInfoTag::CreateFromEpg(epgTag, false); + + if (!newTimer) + { + HELPERS::ShowOKDialogText( + CVariant{19033}, // "Information" + bCreateRule ? CVariant{19095} // Timer rule creation failed. Unsupported timer type. + : CVariant{19094}); // Timer creation failed. Unsupported timer type. + return false; + } + } + + if (bShowTimerSettings) + { + if (!ShowTimerSettings(newTimer)) + return false; + } + + return AddTimer(newTimer); +} + +bool CPVRGUIActionsTimers::AddTimer(const std::shared_ptr<CPVRTimerInfoTag>& item) const +{ + if (!item->Channel() && !item->GetTimerType()->IsEpgBasedTimerRule()) + { + CLog::LogF(LOGERROR, "No channel given"); + HELPERS::ShowOKDialogText( + CVariant{257}, + CVariant{ + 19109}); // "Error", "Could not save the timer. Check the log for more information about this message." + return false; + } + + if (!item->IsTimerRule() && item->GetEpgInfoTag() && !item->GetEpgInfoTag()->IsRecordable()) + { + HELPERS::ShowOKDialogText( + CVariant{19033}, + CVariant{19189}); // "Information", "The PVR backend does not allow to record this event." + return false; + } + + if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalLock( + item->Channel()) != ParentalCheckResult::SUCCESS) + return false; + + if (!CServiceBroker::GetPVRManager().Timers()->AddTimer(item)) + { + HELPERS::ShowOKDialogText( + CVariant{257}, + CVariant{ + 19109}); // "Error", "Could not save the timer. Check the log for more information about this message." + return false; + } + + return true; +} + +namespace +{ +enum PVRRECORD_INSTANTRECORDACTION +{ + NONE = -1, + RECORD_CURRENT_SHOW = 0, + RECORD_INSTANTRECORDTIME = 1, + ASK = 2, + RECORD_30_MINUTES = 3, + RECORD_60_MINUTES = 4, + RECORD_120_MINUTES = 5, + RECORD_NEXT_SHOW = 6 +}; + +class InstantRecordingActionSelector +{ +public: + explicit InstantRecordingActionSelector(int iInstantRecordTime); + virtual ~InstantRecordingActionSelector() = default; + + void AddAction(PVRRECORD_INSTANTRECORDACTION eAction, const std::string& title); + void PreSelectAction(PVRRECORD_INSTANTRECORDACTION eAction); + PVRRECORD_INSTANTRECORDACTION Select(); + +private: + int m_iInstantRecordTime; + CGUIDialogSelect* m_pDlgSelect; // not owner! + std::map<PVRRECORD_INSTANTRECORDACTION, int> m_actions; +}; + +InstantRecordingActionSelector::InstantRecordingActionSelector(int iInstantRecordTime) + : m_iInstantRecordTime(iInstantRecordTime), + m_pDlgSelect(CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>( + WINDOW_DIALOG_SELECT)) +{ + if (m_pDlgSelect) + { + m_pDlgSelect->Reset(); + m_pDlgSelect->SetMultiSelection(false); + m_pDlgSelect->SetHeading(CVariant{19086}); // Instant recording action + } + else + { + CLog::LogF(LOGERROR, "Unable to obtain WINDOW_DIALOG_SELECT instance"); + } +} + +void InstantRecordingActionSelector::AddAction(PVRRECORD_INSTANTRECORDACTION eAction, + const std::string& title) +{ + if (m_actions.find(eAction) == m_actions.end()) + { + switch (eAction) + { + case RECORD_INSTANTRECORDTIME: + m_pDlgSelect->Add( + StringUtils::Format(g_localizeStrings.Get(19090), + m_iInstantRecordTime)); // Record next <default duration> minutes + break; + case RECORD_30_MINUTES: + m_pDlgSelect->Add( + StringUtils::Format(g_localizeStrings.Get(19090), 30)); // Record next 30 minutes + break; + case RECORD_60_MINUTES: + m_pDlgSelect->Add( + StringUtils::Format(g_localizeStrings.Get(19090), 60)); // Record next 60 minutes + break; + case RECORD_120_MINUTES: + m_pDlgSelect->Add( + StringUtils::Format(g_localizeStrings.Get(19090), 120)); // Record next 120 minutes + break; + case RECORD_CURRENT_SHOW: + m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19091), + title)); // Record current show (<title>) + break; + case RECORD_NEXT_SHOW: + m_pDlgSelect->Add(StringUtils::Format(g_localizeStrings.Get(19092), + title)); // Record next show (<title>) + break; + case NONE: + case ASK: + default: + return; + } + + m_actions.insert(std::make_pair(eAction, static_cast<int>(m_actions.size()))); + } +} + +void InstantRecordingActionSelector::PreSelectAction(PVRRECORD_INSTANTRECORDACTION eAction) +{ + const auto& it = m_actions.find(eAction); + if (it != m_actions.end()) + m_pDlgSelect->SetSelected(it->second); +} + +PVRRECORD_INSTANTRECORDACTION InstantRecordingActionSelector::Select() +{ + PVRRECORD_INSTANTRECORDACTION eAction = NONE; + + m_pDlgSelect->Open(); + + if (m_pDlgSelect->IsConfirmed()) + { + int iSelection = m_pDlgSelect->GetSelectedItem(); + const auto it = + std::find_if(m_actions.cbegin(), m_actions.cend(), + [iSelection](const auto& action) { return action.second == iSelection; }); + + if (it != m_actions.cend()) + eAction = (*it).first; + } + + return eAction; +} + +} // unnamed namespace + +bool CPVRGUIActionsTimers::ToggleRecordingOnPlayingChannel() +{ + const std::shared_ptr<CPVRChannel> channel = + CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel(); + if (channel && channel->CanRecord()) + return SetRecordingOnChannel( + channel, !CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel)); + + return false; +} + +bool CPVRGUIActionsTimers::SetRecordingOnChannel(const std::shared_ptr<CPVRChannel>& channel, + bool bOnOff) +{ + bool bReturn = false; + + if (!channel) + return bReturn; + + if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalLock(channel) != + ParentalCheckResult::SUCCESS) + return bReturn; + + const std::shared_ptr<CPVRClient> client = + CServiceBroker::GetPVRManager().GetClient(channel->ClientID()); + if (client && client->GetClientCapabilities().SupportsTimers()) + { + /* timers are supported on this channel */ + if (bOnOff && !CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel)) + { + std::shared_ptr<CPVREpgInfoTag> epgTag; + int iDuration = m_settings.GetIntValue(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME); + + int iAction = m_settings.GetIntValue(CSettings::SETTING_PVRRECORD_INSTANTRECORDACTION); + switch (iAction) + { + case RECORD_CURRENT_SHOW: + epgTag = channel->GetEPGNow(); + break; + + case RECORD_INSTANTRECORDTIME: + epgTag.reset(); + break; + + case ASK: + { + PVRRECORD_INSTANTRECORDACTION ePreselect = RECORD_INSTANTRECORDTIME; + const int iDurationDefault = + m_settings.GetIntValue(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME); + InstantRecordingActionSelector selector(iDurationDefault); + std::shared_ptr<CPVREpgInfoTag> epgTagNext; + + // fixed length recordings + selector.AddAction(RECORD_30_MINUTES, ""); + selector.AddAction(RECORD_60_MINUTES, ""); + selector.AddAction(RECORD_120_MINUTES, ""); + + if (iDurationDefault != 30 && iDurationDefault != 60 && iDurationDefault != 120) + selector.AddAction(RECORD_INSTANTRECORDTIME, ""); + + // epg-based recordings + epgTag = channel->GetEPGNow(); + if (epgTag) + { + bool bLocked = CServiceBroker::GetPVRManager().IsParentalLocked(epgTag); + + // "now" + const std::string currentTitle = + bLocked ? g_localizeStrings.Get(19266) /* Parental locked */ : epgTag->Title(); + selector.AddAction(RECORD_CURRENT_SHOW, currentTitle); + ePreselect = RECORD_CURRENT_SHOW; + + // "next" + epgTagNext = channel->GetEPGNext(); + if (epgTagNext) + { + const std::string nextTitle = bLocked + ? g_localizeStrings.Get(19266) /* Parental locked */ + : epgTagNext->Title(); + selector.AddAction(RECORD_NEXT_SHOW, nextTitle); + + // be smart. if current show is almost over, preselect next show. + if (epgTag->ProgressPercentage() > 90.0f) + ePreselect = RECORD_NEXT_SHOW; + } + } + + if (ePreselect == RECORD_INSTANTRECORDTIME) + { + if (iDurationDefault == 30) + ePreselect = RECORD_30_MINUTES; + else if (iDurationDefault == 60) + ePreselect = RECORD_60_MINUTES; + else if (iDurationDefault == 120) + ePreselect = RECORD_120_MINUTES; + } + + selector.PreSelectAction(ePreselect); + + PVRRECORD_INSTANTRECORDACTION eSelected = selector.Select(); + switch (eSelected) + { + case NONE: + return false; // dialog canceled + + case RECORD_30_MINUTES: + iDuration = 30; + epgTag.reset(); + break; + + case RECORD_60_MINUTES: + iDuration = 60; + epgTag.reset(); + break; + + case RECORD_120_MINUTES: + iDuration = 120; + epgTag.reset(); + break; + + case RECORD_INSTANTRECORDTIME: + iDuration = iDurationDefault; + epgTag.reset(); + break; + + case RECORD_CURRENT_SHOW: + break; + + case RECORD_NEXT_SHOW: + epgTag = epgTagNext; + break; + + default: + CLog::LogF(LOGERROR, + "Unknown instant record action selection ({}), defaulting to fixed " + "length recording.", + static_cast<int>(eSelected)); + epgTag.reset(); + break; + } + break; + } + + default: + CLog::LogF(LOGERROR, + "Unknown instant record action setting value ({}), defaulting to fixed " + "length recording.", + iAction); + break; + } + + const std::shared_ptr<CPVRTimerInfoTag> newTimer( + epgTag ? CPVRTimerInfoTag::CreateFromEpg(epgTag, false) + : CPVRTimerInfoTag::CreateInstantTimerTag(channel, iDuration)); + + if (newTimer) + bReturn = CServiceBroker::GetPVRManager().Timers()->AddTimer(newTimer); + + if (!bReturn) + HELPERS::ShowOKDialogText( + CVariant{257}, + CVariant{ + 19164}); // "Error", "Could not start recording. Check the log for more information about this message." + } + else if (!bOnOff && CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel)) + { + /* delete active timers */ + bReturn = + CServiceBroker::GetPVRManager().Timers()->DeleteTimersOnChannel(channel, true, true); + + if (!bReturn) + HELPERS::ShowOKDialogText( + CVariant{257}, + CVariant{ + 19170}); // "Error", "Could not stop recording. Check the log for more information about this message." + } + } + + return bReturn; +} + +bool CPVRGUIActionsTimers::ToggleTimer(const CFileItemPtr& item) const +{ + if (!item->HasEPGInfoTag()) + return false; + + const std::shared_ptr<CPVRTimerInfoTag> timer(CPVRItem(item).GetTimerInfoTag()); + if (timer) + { + if (timer->IsRecording()) + return StopRecording(item); + else + return DeleteTimer(item); + } + else + return AddTimer(item, false); +} + +bool CPVRGUIActionsTimers::ToggleTimerState(const CFileItemPtr& item) const +{ + if (!item->HasPVRTimerInfoTag()) + return false; + + const std::shared_ptr<CPVRTimerInfoTag> timer(item->GetPVRTimerInfoTag()); + if (timer->m_state == PVR_TIMER_STATE_DISABLED) + timer->m_state = PVR_TIMER_STATE_SCHEDULED; + else + timer->m_state = PVR_TIMER_STATE_DISABLED; + + if (CServiceBroker::GetPVRManager().Timers()->UpdateTimer(timer)) + return true; + + HELPERS::ShowOKDialogText( + CVariant{257}, + CVariant{ + 19263}); // "Error", "Could not update the timer. Check the log for more information about this message." + return false; +} + +bool CPVRGUIActionsTimers::EditTimer(const CFileItemPtr& item) const +{ + const std::shared_ptr<CPVRTimerInfoTag> timer(CPVRItem(item).GetTimerInfoTag()); + if (!timer) + { + CLog::LogF(LOGERROR, "No timer!"); + return false; + } + + // clone the timer. + const std::shared_ptr<CPVRTimerInfoTag> newTimer(new CPVRTimerInfoTag); + newTimer->UpdateEntry(timer); + + if (ShowTimerSettings(newTimer) && + (!timer->GetTimerType()->IsReadOnly() || timer->GetTimerType()->SupportsEnableDisable())) + { + if (newTimer->GetTimerType() == timer->GetTimerType()) + { + if (CServiceBroker::GetPVRManager().Timers()->UpdateTimer(newTimer)) + return true; + + HELPERS::ShowOKDialogText( + CVariant{257}, + CVariant{ + 19263}); // "Error", "Could not update the timer. Check the log for more information about this message." + return false; + } + else + { + // timer type changed. delete the original timer, then create the new timer. this order is + // important. for instance, the new timer might be a rule which schedules the original timer. + // deleting the original timer after creating the rule would do literally this and we would + // end up with one timer missing wrt to the rule defined by the new timer. + if (DeleteTimer(timer, timer->IsRecording(), false)) + { + if (AddTimer(newTimer)) + return true; + + // rollback. + return AddTimer(timer); + } + } + } + return false; +} + +bool CPVRGUIActionsTimers::EditTimerRule(const CFileItemPtr& item) const +{ + const std::shared_ptr<CFileItem> parentTimer = GetTimerRule(item); + if (parentTimer) + return EditTimer(parentTimer); + + return false; +} + +std::shared_ptr<CFileItem> CPVRGUIActionsTimers::GetTimerRule( + const std::shared_ptr<CFileItem>& item) const +{ + std::shared_ptr<CPVRTimerInfoTag> timer; + if (item && item->HasEPGInfoTag()) + timer = CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(item->GetEPGInfoTag()); + else if (item && item->HasPVRTimerInfoTag()) + timer = item->GetPVRTimerInfoTag(); + + if (timer) + { + timer = CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer); + if (timer) + return std::make_shared<CFileItem>(timer); + } + return {}; +} + +bool CPVRGUIActionsTimers::DeleteTimer(const CFileItemPtr& item) const +{ + return DeleteTimer(item, false, false); +} + +bool CPVRGUIActionsTimers::DeleteTimerRule(const CFileItemPtr& item) const +{ + return DeleteTimer(item, false, true); +} + +bool CPVRGUIActionsTimers::DeleteTimer(const CFileItemPtr& item, + bool bIsRecording, + bool bDeleteRule) const +{ + std::shared_ptr<CPVRTimerInfoTag> timer; + const std::shared_ptr<CPVRRecording> recording(CPVRItem(item).GetRecording()); + if (recording) + timer = recording->GetRecordingTimer(); + + if (!timer) + timer = CPVRItem(item).GetTimerInfoTag(); + + if (!timer) + { + CLog::LogF(LOGERROR, "No timer!"); + return false; + } + + if (bDeleteRule && !timer->IsTimerRule()) + timer = CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer); + + if (!timer) + { + CLog::LogF(LOGERROR, "No timer rule!"); + return false; + } + + if (bIsRecording) + { + if (ConfirmStopRecording(timer)) + { + if (CServiceBroker::GetPVRManager().Timers()->DeleteTimer(timer, true, false) == + TimerOperationResult::OK) + return true; + + HELPERS::ShowOKDialogText( + CVariant{257}, + CVariant{ + 19170}); // "Error", "Could not stop recording. Check the log for more information about this message." + return false; + } + } + else if (!timer->GetTimerType()->AllowsDelete()) + { + return false; + } + else + { + bool bAlsoDeleteRule(false); + if (ConfirmDeleteTimer(timer, bAlsoDeleteRule)) + return DeleteTimer(timer, false, bAlsoDeleteRule); + } + return false; +} + +bool CPVRGUIActionsTimers::DeleteTimer(const std::shared_ptr<CPVRTimerInfoTag>& timer, + bool bIsRecording, + bool bDeleteRule) const +{ + TimerOperationResult result = + CServiceBroker::GetPVRManager().Timers()->DeleteTimer(timer, bIsRecording, bDeleteRule); + switch (result) + { + case TimerOperationResult::RECORDING: + { + // recording running. ask the user if it should be deleted anyway + if (HELPERS::ShowYesNoDialogText( + CVariant{122}, // "Confirm delete" + CVariant{ + 19122}) // "This timer is still recording. Are you sure you want to delete this timer?" + != HELPERS::DialogResponse::CHOICE_YES) + return false; + + return DeleteTimer(timer, true, bDeleteRule); + } + case TimerOperationResult::OK: + { + return true; + } + case TimerOperationResult::FAILED: + { + HELPERS::ShowOKDialogText( + CVariant{257}, + CVariant{ + 19110}); // "Error", "Could not delete the timer. Check the log for more information about this message." + return false; + } + default: + { + CLog::LogF(LOGERROR, "Unhandled TimerOperationResult ({})!", static_cast<int>(result)); + break; + } + } + return false; +} + +bool CPVRGUIActionsTimers::ConfirmDeleteTimer(const std::shared_ptr<CPVRTimerInfoTag>& timer, + bool& bDeleteRule) const +{ + bool bConfirmed(false); + const std::shared_ptr<CPVRTimerInfoTag> parentTimer( + CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer)); + + if (parentTimer && parentTimer->GetTimerType()->AllowsDelete()) + { + // timer was scheduled by a deletable timer rule. prompt user for confirmation for deleting the timer rule, including scheduled timers. + bool bCancel(false); + bDeleteRule = CGUIDialogYesNo::ShowAndGetInput( + CVariant{122}, // "Confirm delete" + CVariant{ + 840}, // "Do you want to delete only this timer or also the timer rule that has scheduled it?" + CVariant{""}, CVariant{timer->Title()}, bCancel, CVariant{841}, // "Only this" + CVariant{593}, // "All" + 0); // no autoclose + bConfirmed = !bCancel; + } + else + { + bDeleteRule = false; + + // prompt user for confirmation for deleting the timer + bConfirmed = CGUIDialogYesNo::ShowAndGetInput( + CVariant{122}, // "Confirm delete" + timer->IsTimerRule() + ? CVariant{845} + // "Are you sure you want to delete this timer rule and all timers it has scheduled?" + : CVariant{846}, // "Are you sure you want to delete this timer?" + CVariant{""}, CVariant{timer->Title()}); + } + + return bConfirmed; +} + +bool CPVRGUIActionsTimers::StopRecording(const CFileItemPtr& item) const +{ + if (!DeleteTimer(item, true, false)) + return false; + + CServiceBroker::GetPVRManager().TriggerRecordingsUpdate(); + return true; +} + +bool CPVRGUIActionsTimers::ConfirmStopRecording( + const std::shared_ptr<CPVRTimerInfoTag>& timer) const +{ + return CGUIDialogYesNo::ShowAndGetInput( + CVariant{847}, // "Confirm stop recording" + CVariant{848}, // "Are you sure you want to stop this recording?" + CVariant{""}, CVariant{timer->Title()}); +} + +namespace +{ +std::string GetAnnouncerText(const std::shared_ptr<CPVRTimerInfoTag>& timer, int idEpg, int idNoEpg) +{ + std::string text; + if (timer->IsEpgBased()) + { + text = StringUtils::Format(g_localizeStrings.Get(idEpg), + timer->Title(), // tv show title + timer->ChannelName(), + timer->StartAsLocalTime().GetAsLocalizedDateTime(false, false)); + } + else + { + text = StringUtils::Format(g_localizeStrings.Get(idNoEpg), timer->ChannelName(), + timer->StartAsLocalTime().GetAsLocalizedDateTime(false, false)); + } + return text; +} + +void AddEventLogEntry(const std::shared_ptr<CPVRTimerInfoTag>& timer, int idEpg, int idNoEpg) +{ + std::string name; + std::string icon; + + const std::shared_ptr<CPVRClient> client = + CServiceBroker::GetPVRManager().GetClient(timer->GetTimerType()->GetClientId()); + if (client) + { + name = client->Name(); + icon = client->Icon(); + } + else + { + name = g_sysinfo.GetAppName(); + icon = "special://xbmc/media/icon256x256.png"; + } + + CPVREventLogJob* job = new CPVREventLogJob; + job->AddEvent(false, // do not display a toast, only log event + false, // info, no error + name, GetAnnouncerText(timer, idEpg, idNoEpg), icon); + CServiceBroker::GetJobManager()->AddJob(job, nullptr); +} +} // unnamed namespace + +void CPVRGUIActionsTimers::AnnounceReminder(const std::shared_ptr<CPVRTimerInfoTag>& timer) const +{ + if (!timer->IsReminder()) + { + CLog::LogF(LOGERROR, "No reminder timer!"); + return; + } + + if (timer->EndAsUTC() < CDateTime::GetUTCDateTime()) + { + // expired. timer end is in the past. write event log entry. + AddEventLogEntry(timer, 19305, 19306); // Deleted missed PVR reminder ... + return; + } + + if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingChannel(timer->Channel())) + { + // no need for an announcement. channel in question is already playing. + return; + } + + // show the reminder dialog + CGUIDialogProgress* dialog = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>( + WINDOW_DIALOG_PROGRESS); + if (!dialog) + return; + + dialog->Reset(); + + dialog->SetHeading(CVariant{19312}); // "PVR reminder" + dialog->ShowChoice(0, CVariant{19165}); // "Switch" + + std::string text = GetAnnouncerText(timer, 19307, 19308); // Reminder for ... + + bool bCanRecord = false; + const std::shared_ptr<CPVRClient> client = + CServiceBroker::GetPVRManager().GetClient(timer->m_iClientId); + if (client && client->GetClientCapabilities().SupportsTimers()) + { + bCanRecord = true; + dialog->ShowChoice(1, CVariant{264}); // "Record" + dialog->ShowChoice(2, CVariant{222}); // "Cancel" + + if (m_settings.GetBoolValue(CSettings::SETTING_PVRREMINDERS_AUTORECORD)) + text += "\n\n" + g_localizeStrings.Get( + 19309); // (Auto-close of this reminder will schedule a recording...) + else if (m_settings.GetBoolValue(CSettings::SETTING_PVRREMINDERS_AUTOSWITCH)) + text += "\n\n" + g_localizeStrings.Get( + 19331); // (Auto-close of this reminder will switch to channel...) + } + else + { + dialog->ShowChoice(1, CVariant{222}); // "Cancel" + } + + dialog->SetText(text); + dialog->SetPercentage(100); + + dialog->Open(); + + int result = CGUIDialogProgress::CHOICE_NONE; + + static constexpr int PROGRESS_TIMESLICE_MILLISECS = 50; + + const int iWait = m_settings.GetIntValue(CSettings::SETTING_PVRREMINDERS_AUTOCLOSEDELAY) * 1000; + int iRemaining = iWait; + while (iRemaining > 0) + { + result = dialog->GetChoice(); + if (result != CGUIDialogProgress::CHOICE_NONE) + break; + + std::this_thread::sleep_for(std::chrono::milliseconds(PROGRESS_TIMESLICE_MILLISECS)); + + iRemaining -= PROGRESS_TIMESLICE_MILLISECS; + dialog->SetPercentage(iRemaining * 100 / iWait); + dialog->Progress(); + } + + dialog->Close(); + + bool bAutoClosed = (iRemaining <= 0); + bool bSwitch = (result == 0); + bool bRecord = (result == 1); + + if (bAutoClosed) + { + bRecord = (bCanRecord && m_settings.GetBoolValue(CSettings::SETTING_PVRREMINDERS_AUTORECORD)); + bSwitch = m_settings.GetBoolValue(CSettings::SETTING_PVRREMINDERS_AUTOSWITCH); + } + + if (bRecord) + { + std::shared_ptr<CPVRTimerInfoTag> newTimer; + + std::shared_ptr<CPVREpgInfoTag> epgTag = timer->GetEpgInfoTag(); + if (epgTag) + { + newTimer = CPVRTimerInfoTag::CreateFromEpg(epgTag, false); + if (newTimer) + { + // an epgtag can only have max one timer - we need to clear the reminder to be able to + // attach the recording timer + DeleteTimer(timer, false, false); + } + } + else + { + int iDuration = (timer->EndAsUTC() - timer->StartAsUTC()).GetSecondsTotal() / 60; + newTimer = CPVRTimerInfoTag::CreateTimerTag(timer->Channel(), timer->StartAsUTC(), iDuration); + } + + if (newTimer) + { + // schedule recording + AddTimer(std::make_shared<CFileItem>(newTimer), false); + } + + if (bAutoClosed) + { + AddEventLogEntry(timer, 19310, + 19311); // Scheduled recording for auto-closed PVR reminder ... + } + } + + if (bSwitch) + { + const std::shared_ptr<CPVRChannelGroupMember> groupMember = + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember( + timer->Channel()); + if (groupMember) + { + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel( + std::make_shared<CFileItem>(groupMember), false); + + if (bAutoClosed) + { + AddEventLogEntry(timer, 19332, + 19333); // Switched channel for auto-closed PVR reminder ... + } + } + } +} + +void CPVRGUIActionsTimers::AnnounceReminders() const +{ + // Prevent multiple yesno dialogs, all on same call stack, due to gui message processing while dialog is open. + if (m_bReminderAnnouncementRunning) + return; + + m_bReminderAnnouncementRunning = true; + std::shared_ptr<CPVRTimerInfoTag> timer = + CServiceBroker::GetPVRManager().Timers()->GetNextReminderToAnnnounce(); + while (timer) + { + AnnounceReminder(timer); + timer = CServiceBroker::GetPVRManager().Timers()->GetNextReminderToAnnnounce(); + } + m_bReminderAnnouncementRunning = false; +} diff --git a/xbmc/pvr/guilib/PVRGUIActionsTimers.h b/xbmc/pvr/guilib/PVRGUIActionsTimers.h new file mode 100644 index 0000000000..be3c68629e --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsTimers.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2016-2022 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "pvr/IPVRComponent.h" +#include "pvr/settings/PVRSettings.h" + +#include <memory> + +class CFileItem; + +namespace PVR +{ +class CPVRChannel; +class CPVRTimerInfoTag; + +class CPVRGUIActionsTimers : public IPVRComponent +{ +public: + CPVRGUIActionsTimers(); + virtual ~CPVRGUIActionsTimers() = default; + + /*! + * @brief Open the timer settings dialog to create a new tv or radio timer. + * @param bRadio indicates whether a radio or tv timer shall be created. + * @return true on success, false otherwise. + */ + bool AddTimer(bool bRadio) const; + + /*! + * @brief Create a new timer, either interactive or non-interactive. + * @param item containing epg data to create a timer for. item must be an epg tag or a channel. + * @param bShowTimerSettings is used to control whether a settings dialog will be opened prior + * creating the timer. + * @return true, if the timer was created successfully, false otherwise. + */ + bool AddTimer(const std::shared_ptr<CFileItem>& item, bool bShowTimerSettings) const; + + /*! + * @brief Add a timer to the client. Doesn't add the timer to the container. The backend will + * do this. + * @return True if it was sent correctly, false if not. + */ + bool AddTimer(const std::shared_ptr<CPVRTimerInfoTag>& item) const; + + /*! + * @brief Create a new timer rule, either interactive or non-interactive. + * @param item containing epg data to create a timer rule for. item must be an epg tag or a + * channel. + * @param bShowTimerSettings is used to control whether a settings dialog will be opened prior + * creating the timer rule. + * @param bFallbackToOneShotTimer if no timer rule can be created, try to create a one-shot + * timer instead. + * @return true, if the timer rule was created successfully, false otherwise. + */ + bool AddTimerRule(const std::shared_ptr<CFileItem>& item, + bool bShowTimerSettings, + bool bFallbackToOneShotTimer) const; + + /*! + * @brief Creates or deletes a timer for the given epg tag. + * @param item containing an epg tag. + * @return true on success, false otherwise. + */ + bool ToggleTimer(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Toggles a given timer's enabled/disabled state. + * @param item containing a timer. + * @return true on success, false otherwise. + */ + bool ToggleTimerState(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Open the timer settings dialog to edit an existing timer. + * @param item containing an epg tag or a timer. + * @return true on success, false otherwise. + */ + bool EditTimer(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Open the timer settings dialog to edit an existing timer rule. + * @param item containing an epg tag or a timer. + * @return true on success, false otherwise. + */ + bool EditTimerRule(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Get the timer rule for a given timer + * @param item containing an item to query the timer rule for. item must be a timer or an epg tag. + * @return The timer rule item, or nullptr if none was found. + */ + std::shared_ptr<CFileItem> GetTimerRule(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Delete a timer, always showing a confirmation dialog. + * @param item containing a timer to delete. item must be a timer, an epg tag or a channel. + * @return true, if the timer was deleted successfully, false otherwise. + */ + bool DeleteTimer(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Delete a timer rule, always showing a confirmation dialog. + * @param item containing a timer rule to delete. item must be a timer, an epg tag or a channel. + * @return true, if the timer rule was deleted successfully, false otherwise. + */ + bool DeleteTimerRule(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Toggle recording on the currently playing channel, if any. + * @return True if the recording was started or stopped successfully, false otherwise. + */ + bool ToggleRecordingOnPlayingChannel(); + + /*! + * @brief Start or stop recording on a given channel. + * @param channel the channel to start/stop recording. + * @param bOnOff True to start recording, false to stop. + * @return True if the recording was started or stopped successfully, false otherwise. + */ + bool SetRecordingOnChannel(const std::shared_ptr<CPVRChannel>& channel, bool bOnOff); + + /*! + * @brief Stop a currently active recording, always showing a confirmation dialog. + * @param item containing a recording to stop. item must be a timer, an epg tag or a channel. + * @return true, if the recording was stopped successfully, false otherwise. + */ + bool StopRecording(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Create a new reminder timer, non-interactive. + * @param item containing epg data to create a reminder timer for. item must be an epg tag. + * @return true, if the timer was created successfully, false otherwise. + */ + bool AddReminder(const std::shared_ptr<CFileItem>& item) const; + + /*! + * @brief Announce due reminders, if any. + */ + void AnnounceReminders() const; + +private: + CPVRGUIActionsTimers(const CPVRGUIActionsTimers&) = delete; + CPVRGUIActionsTimers const& operator=(CPVRGUIActionsTimers const&) = delete; + + /*! + * @brief Open the timer settings dialog. + * @param timer containing the timer the settings shall be displayed for. + * @return true, if the dialog was ended successfully, false otherwise. + */ + bool ShowTimerSettings(const std::shared_ptr<CPVRTimerInfoTag>& timer) const; + + /*! + * @brief Add a timer or timer rule, either interactive or non-interactive. + * @param item containing epg data to create a timer or timer rule for. item must be an epg tag + * or a channel. + * @param bCreateteRule denotes whether to create a one-shot timer or a timer rule. + * @param bShowTimerSettings is used to control whether a settings dialog will be opened prior + * creating the timer or timer rule. + * @param bFallbackToOneShotTimer if bCreateteRule is true and no timer rule can be created, try + * to create a one-shot timer instead. + * @return true, if the timer or timer rule was created successfully, false otherwise. + */ + bool AddTimer(const std::shared_ptr<CFileItem>& item, + bool bCreateRule, + bool bShowTimerSettings, + bool bFallbackToOneShotTimer) const; + + /*! + * @brief Delete a timer or timer rule, always showing a confirmation dialog. + * @param item containing a timer or timer rule to delete. item must be a timer, an epg tag or + * a channel. + * @param bIsRecording denotes whether the timer is currently recording (controls correct + * confirmation dialog). + * @param bDeleteRule denotes to delete a timer rule. For convenience, one can pass a timer + * created by a rule. + * @return true, if the timer or timer rule was deleted successfully, false otherwise. + */ + bool DeleteTimer(const std::shared_ptr<CFileItem>& item, + bool bIsRecording, + bool bDeleteRule) const; + + /*! + * @brief Delete a timer or timer rule, showing a confirmation dialog in case a timer currently + * recording shall be deleted. + * @param timer containing a timer or timer rule to delete. + * @param bIsRecording denotes whether the timer is currently recording (controls correct + * confirmation dialog). + * @param bDeleteRule denotes to delete a timer rule. For convenience, one can pass a timer + * created by a rule. + * @return true, if the timer or timer rule was deleted successfully, false otherwise. + */ + bool DeleteTimer(const std::shared_ptr<CPVRTimerInfoTag>& timer, + bool bIsRecording, + bool bDeleteRule) const; + + /*! + * @brief Open a dialog to confirm timer delete. + * @param timer the timer to delete. + * @param bDeleteRule in: ignored. out, for one shot timer scheduled by a timer rule: true to + * also delete the timer rule that has scheduled this timer, false to only delete the one shot + * timer. out, for one shot timer not scheduled by a timer rule: ignored + * @return true, to proceed with delete, false otherwise. + */ + bool ConfirmDeleteTimer(const std::shared_ptr<CPVRTimerInfoTag>& timer, bool& bDeleteRule) const; + + /*! + * @brief Open a dialog to confirm stop recording. + * @param timer the recording to stop (actually the timer to delete). + * @return true, to proceed with delete, false otherwise. + */ + bool ConfirmStopRecording(const std::shared_ptr<CPVRTimerInfoTag>& timer) const; + + /*! + * @brief Announce and process a reminder timer. + * @param timer The reminder timer. + */ + void AnnounceReminder(const std::shared_ptr<CPVRTimerInfoTag>& timer) const; + + CPVRSettings m_settings; + mutable bool m_bReminderAnnouncementRunning{false}; +}; + +namespace GUI +{ +// pretty scope and name +using Timers = CPVRGUIActionsTimers; +} // namespace GUI + +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsUtils.cpp b/xbmc/pvr/guilib/PVRGUIActionsUtils.cpp new file mode 100644 index 0000000000..2f5f8c234e --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsUtils.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PVRGUIActionsUtils.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "pvr/PVRItem.h" +#include "pvr/PVRManager.h" +#include "pvr/PVRPlaybackState.h" +#include "pvr/channels/PVRChannel.h" +#include "pvr/channels/PVRChannelGroupMember.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/epg/EpgInfoTag.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsEPG.h" +#include "pvr/guilib/PVRGUIActionsRecordings.h" +#include "settings/Settings.h" + +#include <memory> +#include <mutex> +#include <string> + +namespace PVR +{ +CPVRGUIActionsUtils::CPVRGUIActionsUtils() + : m_settings({CSettings::SETTING_PVRMANAGER_PRESELECTPLAYINGCHANNEL}) +{ +} + +void CPVRGUIActionsUtils::SetSelectedItemPath(bool bRadio, const std::string& path) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + if (bRadio) + m_selectedItemPathRadio = path; + else + m_selectedItemPathTV = path; +} + +std::string CPVRGUIActionsUtils::GetSelectedItemPath(bool bRadio) const +{ + if (m_settings.GetBoolValue(CSettings::SETTING_PVRMANAGER_PRESELECTPLAYINGCHANNEL)) + { + CPVRManager& mgr = CServiceBroker::GetPVRManager(); + + // if preselect playing channel is activated, return the path of the playing channel, if any. + const std::shared_ptr<CPVRChannel> playingChannel = mgr.PlaybackState()->GetPlayingChannel(); + if (playingChannel && playingChannel->IsRadio() == bRadio) + return mgr.Get<PVR::GUI::Channels>().GetChannelGroupMember(playingChannel)->Path(); + + const std::shared_ptr<CPVREpgInfoTag> playingTag = mgr.PlaybackState()->GetPlayingEpgTag(); + if (playingTag && playingTag->IsRadio() == bRadio) + { + const std::shared_ptr<CPVRChannel> channel = + mgr.ChannelGroups()->GetChannelForEpgTag(playingTag); + if (channel) + return mgr.Get<PVR::GUI::Channels>().GetChannelGroupMember(channel)->Path(); + } + } + + std::unique_lock<CCriticalSection> lock(m_critSection); + return bRadio ? m_selectedItemPathRadio : m_selectedItemPathTV; +} + +bool CPVRGUIActionsUtils::OnInfo(const std::shared_ptr<CFileItem>& item) +{ + if (item->HasPVRRecordingInfoTag()) + { + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().ShowRecordingInfo(item); + } + else if (item->HasPVRChannelInfoTag() || item->HasPVRTimerInfoTag()) + { + return CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo(item); + } + else if (item->HasEPGSearchFilter()) + { + return CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().EditSavedSearch(item); + } + return false; +} + +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsUtils.h b/xbmc/pvr/guilib/PVRGUIActionsUtils.h new file mode 100644 index 0000000000..658a4cb8c1 --- /dev/null +++ b/xbmc/pvr/guilib/PVRGUIActionsUtils.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "pvr/IPVRComponent.h" +#include "pvr/settings/PVRSettings.h" +#include "threads/CriticalSection.h" + +#include <memory> +#include <string> + +class CFileItem; + +namespace PVR +{ +class CPVRGUIActionsUtils : public IPVRComponent +{ +public: + CPVRGUIActionsUtils(); + virtual ~CPVRGUIActionsUtils() = default; + + /*! + * @brief Get the currently selected item path; used across several windows/dialogs to share + * item selection. + * @param bRadio True to query the selected path for PVR radio, false for Live TV. + * @return the path. + */ + std::string GetSelectedItemPath(bool bRadio) const; + + /*! + * @brief Set the currently selected item path; used across several windows/dialogs to share + * item selection. + * @param bRadio True to set the selected path for PVR radio, false for Live TV. + * @param path The new path to set. + */ + void SetSelectedItemPath(bool bRadio, const std::string& path); + + /*! + * @brief Process info action for the given item. + * @param item The item. + */ + bool OnInfo(const std::shared_ptr<CFileItem>& item); + +private: + CPVRGUIActionsUtils(const CPVRGUIActionsUtils&) = delete; + CPVRGUIActionsUtils const& operator=(CPVRGUIActionsUtils const&) = delete; + + mutable CCriticalSection m_critSection; + CPVRSettings m_settings; + std::string m_selectedItemPathTV; + std::string m_selectedItemPathRadio; +}; + +namespace GUI +{ +// pretty scope and name +using Utils = CPVRGUIActionsUtils; +} // namespace GUI + +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIChannelNavigator.cpp b/xbmc/pvr/guilib/PVRGUIChannelNavigator.cpp index e098545a18..cd5e1a427e 100644 --- a/xbmc/pvr/guilib/PVRGUIChannelNavigator.cpp +++ b/xbmc/pvr/guilib/PVRGUIChannelNavigator.cpp @@ -15,7 +15,7 @@ #include "pvr/PVRManager.h" #include "pvr/PVRPlaybackState.h" #include "pvr/channels/PVRChannelGroup.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "threads/SystemClock.h" @@ -192,7 +192,7 @@ namespace PVR } if (item) - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(item, false); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel(item, false); } bool CPVRGUIChannelNavigator::IsPreview() const diff --git a/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp b/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp index 9c18269643..aa926cd8af 100644 --- a/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp +++ b/xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp @@ -28,7 +28,7 @@ #include "pvr/channels/PVRRadioRDSInfoTag.h" #include "pvr/epg/EpgInfoTag.h" #include "pvr/epg/EpgSearchFilter.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" #include "pvr/providers/PVRProvider.h" #include "pvr/providers/PVRProviders.h" #include "pvr/recordings/PVRRecording.h" @@ -471,7 +471,7 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem* item, const CGUIInf case LISTITEM_CHANNEL_NUMBER: { const std::shared_ptr<CPVRChannelGroupMember> groupMember = - CServiceBroker::GetPVRManager().GUIActions()->GetChannelGroupMember(*item); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(*item); if (groupMember) { strValue = groupMember->ChannelNumber().FormattedChannelNumber(); @@ -765,7 +765,7 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem* item, const CGUIInf case LISTITEM_CHANNEL_NUMBER: { const std::shared_ptr<CPVRChannelGroupMember> groupMember = - CServiceBroker::GetPVRManager().GUIActions()->GetChannelGroupMember(*item); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().GetChannelGroupMember(*item); if (groupMember) { strValue = groupMember->ChannelNumber().FormattedChannelNumber(); @@ -995,7 +995,10 @@ bool CPVRGUIInfo::GetPVRLabel(const CFileItem* item, const CGUIInfo& info, std:: CharInfoTotalDiskSpace(strValue); return true; case PVR_CHANNEL_NUMBER_INPUT: - strValue = CServiceBroker::GetPVRManager().GUIActions()->GetChannelNumberInputHandler().GetChannelNumberLabel(); + strValue = CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNumberInputHandler() + .GetChannelNumberLabel(); return true; } @@ -1525,7 +1528,10 @@ bool CPVRGUIInfo::GetListItemAndPlayerBool(const CFileItem* item, const CGUIInfo case PLAYER_IS_CHANNEL_PREVIEW_ACTIVE: if (item->IsPVRChannel()) { - if (CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().IsPreviewAndShowInfo()) + if (CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNavigator() + .IsPreviewAndShowInfo()) { bValue = true; } diff --git a/xbmc/pvr/settings/PVRSettings.cpp b/xbmc/pvr/settings/PVRSettings.cpp index 46b3b61304..f28651a655 100644 --- a/xbmc/pvr/settings/PVRSettings.cpp +++ b/xbmc/pvr/settings/PVRSettings.cpp @@ -12,7 +12,7 @@ #include "guilib/LocalizeStrings.h" #include "pvr/PVRManager.h" #include "pvr/addons/PVRClients.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsParentalControl.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "settings/lib/SettingsManager.h" @@ -227,5 +227,6 @@ bool CPVRSettings::CheckParentalPin(const std::string& condition, const std::shared_ptr<const CSetting>& setting, void* data) { - return CServiceBroker::GetPVRManager().GUIActions()->CheckParentalPIN() == ParentalCheckResult::SUCCESS; + return CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalPIN() == + ParentalCheckResult::SUCCESS; } diff --git a/xbmc/pvr/windows/GUIWindowPVRBase.cpp b/xbmc/pvr/windows/GUIWindowPVRBase.cpp index 7988cbdd3f..bc477c2675 100644 --- a/xbmc/pvr/windows/GUIWindowPVRBase.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRBase.cpp @@ -28,7 +28,7 @@ #include "pvr/channels/PVRChannelGroups.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/filesystem/PVRGUIDirectory.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsUtils.h" #include "utils/Variant.h" #include "utils/log.h" @@ -144,7 +144,8 @@ CGUIWindowPVRBase::~CGUIWindowPVRBase() void CGUIWindowPVRBase::UpdateSelectedItemPath() { - CServiceBroker::GetPVRManager().GUIActions()->SetSelectedItemPath(m_bRadio, m_viewControl.GetSelectedItemPath()); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Utils>().SetSelectedItemPath( + m_bRadio, m_viewControl.GetSelectedItemPath()); } void CGUIWindowPVRBase::RegisterObservers() @@ -288,7 +289,8 @@ void CGUIWindowPVRBase::OnInitWindow() CGUIMediaWindow::OnInitWindow(); // mark item as selected by channel path - m_viewControl.SetSelectedItem(CServiceBroker::GetPVRManager().GUIActions()->GetSelectedItemPath(m_bRadio)); + m_viewControl.SetSelectedItem( + CServiceBroker::GetPVRManager().Get<PVR::GUI::Utils>().GetSelectedItemPath(m_bRadio)); // This has to be done after base class OnInitWindow to restore correct selection m_channelGroupsSelector->SelectChannelGroup(GetChannelGroup()); diff --git a/xbmc/pvr/windows/GUIWindowPVRChannels.cpp b/xbmc/pvr/windows/GUIWindowPVRChannels.cpp index 11715153bb..9330aeaaa5 100644 --- a/xbmc/pvr/windows/GUIWindowPVRChannels.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRChannels.cpp @@ -32,7 +32,9 @@ #include "pvr/dialogs/GUIDialogPVRGroupManager.h" #include "pvr/epg/Epg.h" #include "pvr/epg/EpgContainer.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsEPG.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" #include "utils/StringUtils.h" #include "utils/Variant.h" @@ -147,7 +149,10 @@ bool CGUIWindowPVRChannelsBase::OnMessage(CGUIMessage& message) message.GetParam1() == ACTION_MOUSE_LEFT_CLICK) { // If direct channel number input is active, select the entered channel. - if (CServiceBroker::GetPVRManager().GUIActions()->GetChannelNumberInputHandler().CheckInputAndExecuteAction()) + if (CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNumberInputHandler() + .CheckInputAndExecuteAction()) { bReturn = true; break; @@ -163,13 +168,16 @@ bool CGUIWindowPVRChannelsBase::OnMessage(CGUIMessage& message) case ACTION_SELECT_ITEM: case ACTION_MOUSE_LEFT_CLICK: case ACTION_PLAYER_PLAY: - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(m_vecItems->Get(iItem), true); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel( + m_vecItems->Get(iItem), true); break; case ACTION_SHOW_INFO: - CServiceBroker::GetPVRManager().GUIActions()->ShowEPGInfo(m_vecItems->Get(iItem)); + CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo( + m_vecItems->Get(iItem)); break; case ACTION_DELETE_ITEM: - CServiceBroker::GetPVRManager().GUIActions()->HideChannel(m_vecItems->Get(iItem)); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Channels>().HideChannel( + m_vecItems->Get(iItem)); break; case ACTION_CONTEXT_MENU: case ACTION_MOUSE_RIGHT_CLICK: diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp index 720e1dffb5..c5c43fe532 100644 --- a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp @@ -34,7 +34,11 @@ #include "pvr/epg/EpgContainer.h" #include "pvr/epg/EpgInfoTag.h" #include "pvr/guilib/GUIEPGGridContainer.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsChannels.h" +#include "pvr/guilib/PVRGUIActionsEPG.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" +#include "pvr/guilib/PVRGUIActionsTimers.h" +#include "pvr/guilib/PVRGUIActionsUtils.h" #include "pvr/recordings/PVRRecordings.h" #include "pvr/timers/PVRTimers.h" #include "settings/Settings.h" @@ -76,7 +80,7 @@ void CGUIWindowPVRGuideBase::InitEpgGridControl() CPVRManager& mgr = CServiceBroker::GetPVRManager(); const std::shared_ptr<CPVRChannel> channel = - mgr.ChannelGroups()->GetByPath(mgr.GUIActions()->GetSelectedItemPath(m_bRadio)); + mgr.ChannelGroups()->GetByPath(mgr.Get<PVR::GUI::Utils>().GetSelectedItemPath(m_bRadio)); if (channel) { @@ -194,8 +198,8 @@ void CGUIWindowPVRGuideBase::UpdateSelectedItemPath() const std::shared_ptr<CPVRChannelGroupMember> groupMember = epgGridContainer->GetSelectedChannelGroupMember(); if (groupMember) - CServiceBroker::GetPVRManager().GUIActions()->SetSelectedItemPath(m_bRadio, - groupMember->Path()); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Utils>().SetSelectedItemPath( + m_bRadio, groupMember->Path()); } } @@ -224,7 +228,8 @@ bool CGUIWindowPVRGuideBase::Update(const std::string& strDirectory, bool update { CGUIEPGGridContainer* epgGridContainer = GetGridControl(); if (epgGridContainer) - m_bChannelSelectionRestored = epgGridContainer->SetChannel(CServiceBroker::GetPVRManager().GUIActions()->GetSelectedItemPath(m_bRadio)); + m_bChannelSelectionRestored = epgGridContainer->SetChannel( + CServiceBroker::GetPVRManager().Get<PVR::GUI::Utils>().GetSelectedItemPath(m_bRadio)); } return bReturn; @@ -410,7 +415,10 @@ bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message) message.GetParam1() == ACTION_MOUSE_LEFT_CLICK) { // If direct channel number input is active, select the entered channel. - if (CServiceBroker::GetPVRManager().GUIActions()->GetChannelNumberInputHandler().CheckInputAndExecuteAction()) + if (CServiceBroker::GetPVRManager() + .Get<PVR::GUI::Channels>() + .GetChannelNumberInputHandler() + .CheckInputAndExecuteAction()) { bReturn = true; break; @@ -432,19 +440,21 @@ bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message) bReturn = true; break; case EPG_SELECT_ACTION_SWITCH: - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(pItem, true); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel(pItem, + true); bReturn = true; break; case EPG_SELECT_ACTION_PLAY_RECORDING: - CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(pItem, true); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording(pItem, + true); bReturn = true; break; case EPG_SELECT_ACTION_INFO: - CServiceBroker::GetPVRManager().GUIActions()->ShowEPGInfo(pItem); + CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo(pItem); bReturn = true; break; case EPG_SELECT_ACTION_RECORD: - CServiceBroker::GetPVRManager().GUIActions()->ToggleTimer(pItem); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().ToggleTimer(pItem); bReturn = true; break; case EPG_SELECT_ACTION_SMART_SELECT: @@ -459,13 +469,14 @@ bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message) if (start <= now && now <= end) { // current event - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(pItem, true); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel( + pItem, true); } else if (now < start) { // future event if (CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(tag)) - CServiceBroker::GetPVRManager().GUIActions()->EditTimer(pItem); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().EditTimer(pItem); else { bool bCanRecord = true; @@ -485,20 +496,23 @@ bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message) CVariant{iTextID}, CVariant{iNoButtonID}, CVariant{19165}); // Yes => "Switch" if (ret == HELPERS::DialogResponse::CHOICE_NO) - CServiceBroker::GetPVRManager().GUIActions()->AddTimer(pItem, false); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddTimer(pItem, + false); else if (ret == HELPERS::DialogResponse::CHOICE_YES) - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(pItem, true); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel( + pItem, true); } } else { // past event if (CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(tag)) - CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(pItem, true); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording( + pItem, true); else if (tag->IsPlayable()) - CServiceBroker::GetPVRManager().GUIActions()->PlayEpgTag(pItem); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayEpgTag(pItem); else - CServiceBroker::GetPVRManager().GUIActions()->ShowEPGInfo(pItem); + CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo(pItem); } bReturn = true; } @@ -507,19 +521,21 @@ bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message) } break; case ACTION_SHOW_INFO: - CServiceBroker::GetPVRManager().GUIActions()->ShowEPGInfo(pItem); + CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo(pItem); bReturn = true; break; case ACTION_PLAYER_PLAY: - CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(pItem, true); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().SwitchToChannel(pItem, + true); bReturn = true; break; case ACTION_RECORD: - CServiceBroker::GetPVRManager().GUIActions()->ToggleTimer(pItem); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().ToggleTimer(pItem); bReturn = true; break; case ACTION_PVR_SHOW_TIMER_RULE: - CServiceBroker::GetPVRManager().GUIActions()->AddTimerRule(pItem, true, false); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddTimerRule(pItem, true, + false); bReturn = true; break; case ACTION_CONTEXT_MENU: diff --git a/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp b/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp index 05a1506f76..3587dfb2df 100644 --- a/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp @@ -18,7 +18,8 @@ #include "input/actions/Action.h" #include "input/actions/ActionIDs.h" #include "pvr/PVRManager.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsPlayback.h" +#include "pvr/guilib/PVRGUIActionsRecordings.h" #include "pvr/recordings/PVRRecording.h" #include "pvr/recordings/PVRRecordings.h" #include "pvr/recordings/PVRRecordingsPath.h" @@ -236,7 +237,8 @@ bool CGUIWindowPVRRecordingsBase::OnMessage(CGUIMessage& message) if (message.GetParam1() == ACTION_PLAYER_PLAY) { - CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(item, true /* check resume */); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording( + item, true /* check resume */); bReturn = true; } else @@ -248,15 +250,18 @@ bool CGUIWindowPVRRecordingsBase::OnMessage(CGUIMessage& message) bReturn = true; break; case SELECT_ACTION_PLAY_OR_RESUME: - CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(item, true /* check resume */); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording( + item, true /* check resume */); bReturn = true; break; case SELECT_ACTION_RESUME: - CServiceBroker::GetPVRManager().GUIActions()->ResumePlayRecording(item, true /* fall back to play if no resume possible */); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().ResumePlayRecording( + item, true /* fall back to play if no resume possible */); bReturn = true; break; case SELECT_ACTION_INFO: - CServiceBroker::GetPVRManager().GUIActions()->ShowRecordingInfo(item); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().ShowRecordingInfo( + item); bReturn = true; break; default: @@ -272,11 +277,11 @@ bool CGUIWindowPVRRecordingsBase::OnMessage(CGUIMessage& message) bReturn = true; break; case ACTION_SHOW_INFO: - CServiceBroker::GetPVRManager().GUIActions()->ShowRecordingInfo(item); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().ShowRecordingInfo(item); bReturn = true; break; case ACTION_DELETE_ITEM: - CServiceBroker::GetPVRManager().GUIActions()->DeleteRecording(item); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().DeleteRecording(item); bReturn = true; break; default: @@ -342,7 +347,7 @@ bool CGUIWindowPVRRecordingsBase::OnContextButtonDeleteAll(CFileItem* item, CONT { if (button == CONTEXT_BUTTON_DELETE_ALL) { - CServiceBroker::GetPVRManager().GUIActions()->DeleteAllRecordingsFromTrash(); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().DeleteAllRecordingsFromTrash(); return true; } diff --git a/xbmc/pvr/windows/GUIWindowPVRSearch.cpp b/xbmc/pvr/windows/GUIWindowPVRSearch.cpp index 51ca8eb48d..fbe631a521 100644 --- a/xbmc/pvr/windows/GUIWindowPVRSearch.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRSearch.cpp @@ -27,7 +27,8 @@ #include "pvr/epg/EpgInfoTag.h" #include "pvr/epg/EpgSearchFilter.h" #include "pvr/epg/EpgSearchPath.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsEPG.h" +#include "pvr/guilib/PVRGUIActionsTimers.h" #include "pvr/recordings/PVRRecording.h" #include "threads/IRunnable.h" #include "utils/URIUtils.h" @@ -262,7 +263,7 @@ bool CGUIWindowPVRSearchBase::OnMessage(CGUIMessage& message) } else { - CServiceBroker::GetPVRManager().GUIActions()->ShowEPGInfo(pItem); + CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo(pItem); } return true; } @@ -273,7 +274,7 @@ bool CGUIWindowPVRSearchBase::OnMessage(CGUIMessage& message) return true; case ACTION_RECORD: - CServiceBroker::GetPVRManager().GUIActions()->ToggleTimer(pItem); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().ToggleTimer(pItem); return true; } } diff --git a/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp b/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp index 752976b8b8..8c3be2f609 100644 --- a/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp @@ -17,7 +17,7 @@ #include "input/actions/Action.h" #include "input/actions/ActionIDs.h" #include "pvr/PVRManager.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsTimers.h" #include "pvr/timers/PVRTimerInfoTag.h" #include "pvr/timers/PVRTimersPath.h" #include "settings/Settings.h" @@ -140,7 +140,8 @@ bool CGUIWindowPVRTimersBase::OnMessage(CGUIMessage& message) OnPopupMenu(iItem); break; case ACTION_DELETE_ITEM: - CServiceBroker::GetPVRManager().GUIActions()->DeleteTimer(m_vecItems->Get(iItem)); + CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().DeleteTimer( + m_vecItems->Get(iItem)); break; default: bReturn = false; @@ -191,9 +192,9 @@ bool CGUIWindowPVRTimersBase::ActionShowTimer(const CFileItemPtr& item) create a new timer and open settings dialog, otherwise open settings for selected timer entry */ if (URIUtils::PathEquals(item->GetPath(), CPVRTimersPath::PATH_ADDTIMER)) - bReturn = CServiceBroker::GetPVRManager().GUIActions()->AddTimer(m_bRadio); + bReturn = CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().AddTimer(m_bRadio); else - bReturn = CServiceBroker::GetPVRManager().GUIActions()->EditTimer(item); + bReturn = CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().EditTimer(item); return bReturn; } diff --git a/xbmc/windows/GUIWindowLoginScreen.cpp b/xbmc/windows/GUIWindowLoginScreen.cpp index 6d0c4b0b9a..b00c2ae853 100644 --- a/xbmc/windows/GUIWindowLoginScreen.cpp +++ b/xbmc/windows/GUIWindowLoginScreen.cpp @@ -25,7 +25,7 @@ #include "profiles/ProfileManager.h" #include "profiles/dialogs/GUIDialogProfileSettings.h" #include "pvr/PVRManager.h" -#include "pvr/guilib/PVRGUIActions.h" +#include "pvr/guilib/PVRGUIActionsPowerManagement.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "utils/StringUtils.h" @@ -128,7 +128,7 @@ bool CGUIWindowLoginScreen::OnAction(const CAction &action) std::string actionName = action.GetName(); StringUtils::ToLower(actionName); if ((actionName.find("shutdown") != std::string::npos) && - CServiceBroker::GetPVRManager().GUIActions()->CanSystemPowerdown()) + CServiceBroker::GetPVRManager().Get<PVR::GUI::PowerManagement>().CanSystemPowerdown()) CBuiltins::GetInstance().Execute(action.GetName()); return true; } |