aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Sommerfeld <kai.sommerfeld@gmx.com>2022-09-28 01:11:27 +0200
committerGitHub <noreply@github.com>2022-09-28 01:11:27 +0200
commitf48d6c361fafc1b4487042147a82ee65933813da (patch)
tree2e40ac2bb375e4c6cad0e4ef81289633f8e33e12
parentbb3f4fe025a50c5ff28013b5f0c21fa9bccea40f (diff)
parent6366a7e455771ed465c549d2a14976b1c0afc726 (diff)
Merge pull request #21928 from ksooo/pvr-refactor-guiactions
[PVR] Refactor CPVRGUIActions
-rw-r--r--xbmc/FileItem.cpp7
-rw-r--r--xbmc/application/Application.cpp35
-rw-r--r--xbmc/application/ApplicationPowerHandling.cpp8
-rw-r--r--xbmc/input/WindowTranslator.cpp20
-rw-r--r--xbmc/interfaces/builtins/PVRBuiltins.cpp4
-rw-r--r--xbmc/interfaces/builtins/PlayerBuiltins.cpp4
-rw-r--r--xbmc/interfaces/json-rpc/PVROperations.cpp18
-rw-r--r--xbmc/interfaces/json-rpc/PlayerOperations.cpp12
-rw-r--r--xbmc/listproviders/DirectoryProvider.cpp4
-rw-r--r--xbmc/pvr/CMakeLists.txt5
-rw-r--r--xbmc/pvr/IPVRComponent.h18
-rw-r--r--xbmc/pvr/PVRComponentRegistration.cpp52
-rw-r--r--xbmc/pvr/PVRComponentRegistration.h22
-rw-r--r--xbmc/pvr/PVRContextMenus.cpp65
-rw-r--r--xbmc/pvr/PVRManager.cpp18
-rw-r--r--xbmc/pvr/PVRManager.h20
-rw-r--r--xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp5
-rw-r--r--xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp18
-rw-r--r--xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp26
-rw-r--r--xbmc/pvr/dialogs/GUIDialogPVRItemsViewBase.cpp4
-rw-r--r--xbmc/pvr/dialogs/GUIDialogPVRRecordingInfo.cpp8
-rw-r--r--xbmc/pvr/guilib/CMakeLists.txt22
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionListener.cpp69
-rw-r--r--xbmc/pvr/guilib/PVRGUIActions.cpp2835
-rw-r--r--xbmc/pvr/guilib/PVRGUIActions.h605
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsChannels.cpp344
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsChannels.h134
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsClients.cpp88
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsClients.h38
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsDatabase.cpp341
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsDatabase.h40
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsEPG.cpp217
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsEPG.h86
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsParentalControl.cpp74
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsParentalControl.h59
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp561
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsPlayback.h151
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsPowerManagement.cpp192
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsPowerManagement.h55
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsRecordings.cpp362
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsRecordings.h114
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsTimers.cpp1010
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsTimers.h236
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsUtils.cpp87
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsUtils.h66
-rw-r--r--xbmc/pvr/guilib/PVRGUIChannelNavigator.cpp4
-rw-r--r--xbmc/pvr/guilib/guiinfo/PVRGUIInfo.cpp16
-rw-r--r--xbmc/pvr/settings/PVRSettings.cpp5
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRBase.cpp8
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRChannels.cpp18
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRGuide.cpp58
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRRecordings.cpp21
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRSearch.cpp7
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp9
-rw-r--r--xbmc/windows/GUIWindowLoginScreen.cpp4
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;
}