2 * Copyright (C) 2012-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "GUIWindowPVRGuide.h"
12 #include "FileItemList.h"
13 #include "GUIUserMessages.h"
14 #include "ServiceBroker.h"
15 #include "addons/Skin.h"
16 #include "dialogs/GUIDialogBusy.h"
17 #include "dialogs/GUIDialogContextMenu.h"
18 #include "dialogs/GUIDialogNumeric.h"
19 #include "guilib/GUIMessage.h"
20 #include "guilib/GUIWindowManager.h"
21 #include "guilib/LocalizeStrings.h"
22 #include "input/actions/Action.h"
23 #include "input/actions/ActionIDs.h"
24 #include "messaging/ApplicationMessenger.h"
25 #include "messaging/helpers/DialogHelper.h"
26 #include "pvr/PVRItem.h"
27 #include "pvr/PVRManager.h"
28 #include "pvr/PVRPlaybackState.h"
29 #include "pvr/channels/PVRChannel.h"
30 #include "pvr/channels/PVRChannelGroup.h"
31 #include "pvr/channels/PVRChannelGroupMember.h"
32 #include "pvr/channels/PVRChannelGroupsContainer.h"
33 #include "pvr/channels/PVRChannelsPath.h"
34 #include "pvr/epg/EpgChannelData.h"
35 #include "pvr/epg/EpgContainer.h"
36 #include "pvr/epg/EpgInfoTag.h"
37 #include "pvr/guilib/GUIEPGGridContainer.h"
38 #include "pvr/guilib/PVRGUIActionsChannels.h"
39 #include "pvr/guilib/PVRGUIActionsEPG.h"
40 #include "pvr/guilib/PVRGUIActionsPlayback.h"
41 #include "pvr/guilib/PVRGUIActionsTimers.h"
42 #include "pvr/recordings/PVRRecordings.h"
43 #include "pvr/timers/PVRTimers.h"
44 #include "settings/Settings.h"
45 #include "settings/SettingsComponent.h"
46 #include "view/GUIViewState.h"
54 using namespace KODI::MESSAGING
;
56 using namespace std::chrono_literals
;
58 CGUIWindowPVRGuideBase::CGUIWindowPVRGuideBase(bool bRadio
, int id
, const std::string
& xmlFile
)
59 : CGUIWindowPVRBase(bRadio
, id
, xmlFile
)
61 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Channels
>().RegisterChannelNumberInputHandler(this);
64 CGUIWindowPVRGuideBase::~CGUIWindowPVRGuideBase()
66 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Channels
>().DeregisterChannelNumberInputHandler(
69 m_bRefreshTimelineItems
= false;
70 m_bSyncRefreshTimelineItems
= false;
71 StopRefreshTimelineItemsThread();
74 CGUIEPGGridContainer
* CGUIWindowPVRGuideBase::GetGridControl()
76 return dynamic_cast<CGUIEPGGridContainer
*>(GetControl(m_viewControl
.GetCurrentControl()));
79 void CGUIWindowPVRGuideBase::InitEpgGridControl()
81 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
84 CPVRManager
& mgr
= CServiceBroker::GetPVRManager();
86 const std::shared_ptr
<CPVRChannel
> channel
= mgr
.ChannelGroups()->GetByPath(
87 mgr
.Get
<PVR::GUI::Channels
>().GetSelectedChannelPath(m_bRadio
));
91 m_bChannelSelectionRestored
= epgGridContainer
->SetChannel(channel
);
92 epgGridContainer
->JumpToDate(
93 mgr
.PlaybackState()->GetPlaybackTime(channel
->ClientID(), channel
->UniqueID()));
97 m_bChannelSelectionRestored
= false;
98 epgGridContainer
->JumpToNow();
101 if (!epgGridContainer
->HasData())
102 m_bSyncRefreshTimelineItems
= true; // force data update on first window open
105 StartRefreshTimelineItemsThread();
108 void CGUIWindowPVRGuideBase::ClearData()
111 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
112 m_cachedChannelGroup
.reset();
115 CGUIWindowPVRBase::ClearData();
118 void CGUIWindowPVRGuideBase::OnInitWindow()
121 m_viewControl
.SetCurrentView(m_guiState
->GetViewAsControl(), false);
123 if (InitChannelGroup()) // no channels -> lazy init
124 InitEpgGridControl();
126 CGUIWindowPVRBase::OnInitWindow();
129 void CGUIWindowPVRGuideBase::OnDeinitWindow(int nextWindowID
)
131 StopRefreshTimelineItemsThread();
133 m_bChannelSelectionRestored
= false;
136 CServiceBroker::GetGUI()->GetWindowManager().GetDialog(WINDOW_DIALOG_PVR_GUIDE_CONTROLS
);
137 if (dialog
&& dialog
->IsDialogRunning())
142 CGUIWindowPVRBase::OnDeinitWindow(nextWindowID
);
145 void CGUIWindowPVRGuideBase::StartRefreshTimelineItemsThread()
147 StopRefreshTimelineItemsThread();
148 m_refreshTimelineItemsThread
= std::make_unique
<CPVRRefreshTimelineItemsThread
>(this);
149 m_refreshTimelineItemsThread
->Create();
152 void CGUIWindowPVRGuideBase::StopRefreshTimelineItemsThread()
154 if (m_refreshTimelineItemsThread
)
155 m_refreshTimelineItemsThread
->Stop();
158 void CGUIWindowPVRGuideBase::NotifyEvent(const PVREvent
& event
)
160 if (event
== PVREvent::Epg
|| event
== PVREvent::EpgContainer
||
161 event
== PVREvent::ChannelGroupInvalidated
|| event
== PVREvent::ChannelGroup
)
163 m_bRefreshTimelineItems
= true;
164 // no base class call => do async refresh
167 else if (event
== PVREvent::ChannelPlaybackStopped
)
169 if (m_guiState
&& m_guiState
->GetSortMethod().sortBy
== SortByLastPlayed
)
171 // set dirty to force sync refresh
172 m_bSyncRefreshTimelineItems
= true;
176 // do sync refresh if dirty
177 CGUIWindowPVRBase::NotifyEvent(event
);
180 void CGUIWindowPVRGuideBase::SetInvalid()
182 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
183 if (epgGridContainer
)
184 epgGridContainer
->SetInvalid();
186 CGUIWindowPVRBase::SetInvalid();
189 void CGUIWindowPVRGuideBase::GetContextButtons(int itemNumber
, CContextButtons
& buttons
)
191 CGUIWindowPVRBase::GetContextButtons(itemNumber
, buttons
);
193 buttons
.Add(CONTEXT_BUTTON_NAVIGATE
, 19326); // Navigate...
196 void CGUIWindowPVRGuideBase::UpdateSelectedItemPath()
198 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
199 if (epgGridContainer
)
201 const std::shared_ptr
<const CPVRChannelGroupMember
> groupMember
=
202 epgGridContainer
->GetSelectedChannelGroupMember();
204 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Channels
>().SetSelectedChannelPath(
205 m_bRadio
, groupMember
->Path());
209 void CGUIWindowPVRGuideBase::UpdateButtons()
211 CGUIWindowPVRBase::UpdateButtons();
213 SET_CONTROL_LABEL(CONTROL_LABEL_HEADER1
, g_localizeStrings
.Get(19032));
215 const std::shared_ptr
<const CPVRChannelGroup
> group
= GetChannelGroup();
216 SET_CONTROL_LABEL(CONTROL_LABEL_HEADER2
, group
? group
->GroupName() : "");
219 bool CGUIWindowPVRGuideBase::Update(const std::string
& strDirectory
,
220 bool updateFilterPath
/* = true */)
224 // Prevent concurrent updates. Instead, let the timeline items refresh thread pick it up later.
225 m_bRefreshTimelineItems
= true;
229 bool bReturn
= CGUIWindowPVRBase::Update(strDirectory
, updateFilterPath
);
231 if (bReturn
&& !m_bChannelSelectionRestored
)
233 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
234 if (epgGridContainer
)
235 m_bChannelSelectionRestored
= epgGridContainer
->SetChannel(
236 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Channels
>().GetSelectedChannelPath(
243 bool CGUIWindowPVRGuideBase::GetDirectory(const std::string
& strDirectory
, CFileItemList
& items
)
246 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
248 if (m_cachedChannelGroup
&& *m_cachedChannelGroup
!= *GetChannelGroup())
250 // channel group change and not very first open of this window. force immediate update.
251 m_bSyncRefreshTimelineItems
= true;
255 if (m_bSyncRefreshTimelineItems
)
256 m_refreshTimelineItemsThread
->DoRefresh(true);
258 const CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
259 if (epgGridContainer
)
261 const std::unique_ptr
<CFileItemList
> newTimeline
= GetGridControl()->GetCurrentTimeLineItems();
262 items
.RemoveDiscCache(GetID());
263 items
.Assign(*newTimeline
, false);
269 void CGUIWindowPVRGuideBase::FormatAndSort(CFileItemList
& items
)
271 // Speedup: Nothing to do here as sorting was already done in RefreshTimelineItems
275 CFileItemPtr
CGUIWindowPVRGuideBase::GetCurrentListItem(int offset
/*= 0*/)
277 const CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
278 if (epgGridContainer
)
279 return epgGridContainer
->GetSelectedGridItem(offset
);
284 int CGUIWindowPVRGuideBase::GetCurrentListItemIndex(const std::shared_ptr
<const CFileItem
>& item
)
286 return item
? item
->GetProperty("TimelineIndex").asInteger() : -1;
289 bool CGUIWindowPVRGuideBase::ShouldNavigateToGridContainer(int iAction
)
291 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
292 CGUIControl
* control
= GetControl(CONTROL_LSTCHANNELGROUPS
);
293 if (epgGridContainer
&& control
&& GetFocusedControlID() == control
->GetID())
295 int iNavigationId
= control
->GetAction(iAction
).GetNavigation();
296 if (iNavigationId
> 0)
298 control
= epgGridContainer
;
300 this) // navigation target could be the grid control or one of its parent controls.
302 if (iNavigationId
== control
->GetID())
304 // channel group selector control's target for the action is the grid control
307 control
= control
->GetParentControl();
314 bool CGUIWindowPVRGuideBase::OnAction(const CAction
& action
)
316 switch (action
.GetID())
319 case ACTION_MOVE_DOWN
:
320 case ACTION_MOVE_LEFT
:
321 case ACTION_MOVE_RIGHT
:
323 // Check whether grid container is configured as channel group selector's navigation target for the given action.
324 if (ShouldNavigateToGridContainer(action
.GetID()))
326 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
327 if (epgGridContainer
)
329 CGUIWindowPVRBase::OnAction(action
);
331 switch (action
.GetID())
334 epgGridContainer
->GoToBottom();
336 case ACTION_MOVE_DOWN
:
337 epgGridContainer
->GoToTop();
339 case ACTION_MOVE_LEFT
:
340 epgGridContainer
->GoToMostRight();
342 case ACTION_MOVE_RIGHT
:
343 epgGridContainer
->GoToMostLeft();
353 if (GetCurrentDigitCount() == 0)
355 // single zero input is handled by epg grid container
358 // fall-thru is intended
369 AppendChannelNumberCharacter(static_cast<char>(action
.GetID() - REMOTE_0
) + '0');
372 case ACTION_CHANNEL_NUMBER_SEP
:
373 AppendChannelNumberCharacter(CPVRChannelNumber::SEPARATOR
);
377 return CGUIWindowPVRBase::OnAction(action
);
380 void CGUIWindowPVRGuideBase::RefreshView(CGUIMessage
& message
, bool bInitGridControl
)
382 CGUIWindowPVRBase::OnMessage(message
);
384 // force grid data update
385 m_bSyncRefreshTimelineItems
= true;
387 if (bInitGridControl
)
388 InitEpgGridControl();
393 bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage
& message
)
395 bool bReturn
= false;
396 switch (message
.GetMessage())
398 case GUI_MSG_WINDOW_INIT
:
400 const CPVRChannelsPath
path(message
.GetStringParam(0));
401 if (path
.IsValid() && path
.IsChannelGroup())
403 // if a path to a channel group is given we must init
404 // that group instead of last played/selected group
405 m_channelGroupPath
= message
.GetStringParam(0);
410 case GUI_MSG_ITEM_SELECTED
:
411 message
.SetParam1(GetCurrentListItemIndex(GetCurrentListItem()));
415 case GUI_MSG_CLICKED
:
417 if (message
.GetSenderId() == m_viewControl
.GetCurrentControl())
419 if (message
.GetParam1() == ACTION_SELECT_ITEM
||
420 message
.GetParam1() == ACTION_MOUSE_LEFT_CLICK
)
422 // If direct channel number input is active, select the entered channel.
423 if (CServiceBroker::GetPVRManager()
424 .Get
<PVR::GUI::Channels
>()
425 .GetChannelNumberInputHandler()
426 .CheckInputAndExecuteAction())
433 const std::shared_ptr
<CFileItem
> pItem
= GetCurrentListItem();
436 switch (message
.GetParam1())
438 case ACTION_SELECT_ITEM
:
439 case ACTION_MOUSE_LEFT_CLICK
:
440 switch (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
441 CSettings::SETTING_EPG_SELECTACTION
))
443 case EPG_SELECT_ACTION_CONTEXT_MENU
:
444 OnPopupMenu(GetCurrentListItemIndex(pItem
));
447 case EPG_SELECT_ACTION_SWITCH
:
448 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().SwitchToChannel(*pItem
,
452 case EPG_SELECT_ACTION_PLAY_RECORDING
:
453 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().PlayRecording(*pItem
,
457 case EPG_SELECT_ACTION_INFO
:
458 CServiceBroker::GetPVRManager().Get
<PVR::GUI::EPG
>().ShowEPGInfo(*pItem
);
461 case EPG_SELECT_ACTION_RECORD
:
462 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Timers
>().ToggleTimer(*pItem
);
465 case EPG_SELECT_ACTION_SMART_SELECT
:
467 const std::shared_ptr
<const CPVREpgInfoTag
> tag(pItem
->GetEPGInfoTag());
470 const CDateTime
start(tag
->StartAsUTC());
471 const CDateTime
end(tag
->EndAsUTC());
472 const CDateTime
now(CDateTime::GetUTCDateTime());
474 if (start
<= now
&& now
<= end
)
477 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().SwitchToChannel(
480 else if (now
< start
)
483 if (CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(tag
))
484 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Timers
>().EditTimer(*pItem
);
487 bool bCanRecord
= true;
488 const std::shared_ptr
<const CPVRChannel
> channel
=
489 CPVRItem(pItem
).GetChannel();
491 bCanRecord
= channel
->CanRecord();
495 ? 19302 // "Do you want to record the selected programme or to switch to the current programme?"
496 : 19344; // "Do you want to set a reminder for the selected programme or to switch to the current programme?"
497 const int iNoButtonID
= bCanRecord
? 264 // No => "Record"
498 : 826; // "Set reminder"
500 HELPERS::DialogResponse ret
=
501 HELPERS::ShowYesNoDialogText(CVariant
{19096}, // "Smart select"
502 CVariant
{iTextID
}, CVariant
{iNoButtonID
},
503 CVariant
{19165}); // Yes => "Switch"
504 if (ret
== HELPERS::DialogResponse::CHOICE_NO
)
505 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Timers
>().AddTimer(*pItem
,
507 else if (ret
== HELPERS::DialogResponse::CHOICE_YES
)
508 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().SwitchToChannel(
515 if (CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(tag
))
516 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().PlayRecording(
518 else if (tag
->IsPlayable())
519 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().PlayEpgTag(
522 CServiceBroker::GetPVRManager().Get
<PVR::GUI::EPG
>().ShowEPGInfo(*pItem
);
530 case ACTION_SHOW_INFO
:
531 CServiceBroker::GetPVRManager().Get
<PVR::GUI::EPG
>().ShowEPGInfo(*pItem
);
534 case ACTION_PLAYER_PLAY
:
535 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().SwitchToChannel(*pItem
,
540 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Timers
>().ToggleTimer(*pItem
);
543 case ACTION_PVR_SHOW_TIMER_RULE
:
544 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Timers
>().AddTimerRule(*pItem
, true,
548 case ACTION_CONTEXT_MENU
:
549 case ACTION_MOUSE_RIGHT_CLICK
:
550 OnPopupMenu(GetCurrentListItemIndex(pItem
));
556 else if (message
.GetSenderId() == CONTROL_BTNVIEWASICONS
||
557 message
.GetSenderId() == CONTROL_BTNSORTBY
||
558 message
.GetSenderId() == CONTROL_BTNSORTASC
)
560 RefreshView(message
, false);
565 case GUI_MSG_CHANGE_SORT_DIRECTION
:
566 case GUI_MSG_CHANGE_SORT_METHOD
:
567 case GUI_MSG_CHANGE_VIEW_MODE
:
569 RefreshView(message
, message
.GetMessage() == GUI_MSG_CHANGE_VIEW_MODE
);
573 case GUI_MSG_REFRESH_LIST
:
575 switch (static_cast<PVREvent
>(message
.GetParam1()))
577 case PVREvent::ManagerStarted
:
578 if (InitChannelGroup())
579 InitEpgGridControl();
582 case PVREvent::ChannelGroup
:
583 case PVREvent::ChannelGroupInvalidated
:
584 case PVREvent::ClientsInvalidated
:
585 case PVREvent::ChannelPlaybackStopped
:
587 case PVREvent::EpgContainer
:
588 if (InitChannelGroup())
592 case PVREvent::Timers
:
593 case PVREvent::TimersInvalidated
:
602 case GUI_MSG_SYSTEM_WAKE
:
603 GotoCurrentProgramme();
608 return bReturn
|| CGUIWindowPVRBase::OnMessage(message
);
611 bool CGUIWindowPVRGuideBase::OnContextButton(int itemNumber
, CONTEXT_BUTTON button
)
613 if (OnContextButtonNavigate(button
))
616 if (itemNumber
< 0 || itemNumber
>= m_vecItems
->Size())
619 return CGUIMediaWindow::OnContextButton(itemNumber
, button
);
626 class CContextMenuFunctions
: public CContextButtons
629 explicit CContextMenuFunctions(A
* instance
) : m_instance(instance
) {}
631 void Add(bool (A::*function
)(), unsigned int resId
)
633 CContextButtons::Add(size(), resId
);
634 m_functions
.emplace_back(std::bind(function
, m_instance
));
639 if (idx
< 0 || idx
>= static_cast<int>(m_functions
.size()))
642 return m_functions
[idx
]();
646 A
* m_instance
= nullptr;
647 std::vector
<std::function
<bool()>> m_functions
;
650 } // unnamed namespace
652 bool CGUIWindowPVRGuideBase::OnContextButtonNavigate(CONTEXT_BUTTON button
)
654 bool bReturn
= false;
656 if (button
== CONTEXT_BUTTON_NAVIGATE
)
658 if (g_SkinInfo
->HasSkinFile("DialogPVRGuideControls.xml"))
660 // use controls dialog
662 CServiceBroker::GetGUI()->GetWindowManager().GetDialog(WINDOW_DIALOG_PVR_GUIDE_CONTROLS
);
663 if (dialog
&& !dialog
->IsDialogRunning())
671 CContextMenuFunctions
<CGUIWindowPVRGuideBase
> buttons(this);
672 buttons
.Add(&CGUIWindowPVRGuideBase::GotoBegin
, 19063); // First programme
673 buttons
.Add(&CGUIWindowPVRGuideBase::Go12HoursBack
, 19317); // 12 hours back
674 buttons
.Add(&CGUIWindowPVRGuideBase::GotoCurrentProgramme
, 19070); // Current programme
675 buttons
.Add(&CGUIWindowPVRGuideBase::Go12HoursForward
, 19318); // 12 hours forward
676 buttons
.Add(&CGUIWindowPVRGuideBase::GotoEnd
, 19064); // Last programme
677 buttons
.Add(&CGUIWindowPVRGuideBase::OpenDateSelectionDialog
, 19288); // Date selector
678 buttons
.Add(&CGUIWindowPVRGuideBase::GotoFirstChannel
, 19322); // First channel
679 if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingTV() ||
680 CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRadio() ||
681 CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingEpgTag())
682 buttons
.Add(&CGUIWindowPVRGuideBase::GotoPlayingChannel
, 19323); // Playing channel
683 buttons
.Add(&CGUIWindowPVRGuideBase::GotoLastChannel
, 19324); // Last channel
684 buttons
.Add(&CGUIWindowPVRBase::ActivatePreviousChannelGroup
, 19319); // Previous group
685 buttons
.Add(&CGUIWindowPVRBase::ActivateNextChannelGroup
, 19320); // Next group
686 buttons
.Add(&CGUIWindowPVRBase::OpenChannelGroupSelectionDialog
, 19321); // Group selector
689 int lastButtonIdx
= 2; // initially select "Current programme"
691 // loop until canceled
692 while (buttonIdx
>= 0)
694 buttonIdx
= CGUIDialogContextMenu::Show(buttons
, lastButtonIdx
);
695 lastButtonIdx
= buttonIdx
;
696 buttons
.Call(buttonIdx
);
705 bool CGUIWindowPVRGuideBase::RefreshTimelineItems()
707 if (m_bRefreshTimelineItems
|| m_bSyncRefreshTimelineItems
)
709 m_bRefreshTimelineItems
= false;
710 m_bSyncRefreshTimelineItems
= false;
712 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
713 if (epgGridContainer
)
715 const std::shared_ptr
<CPVRChannelGroup
> group(GetChannelGroup());
719 CPVREpgContainer
& epgContainer
= CServiceBroker::GetPVRManager().EpgContainer();
721 const std::pair
<CDateTime
, CDateTime
> dates
= epgContainer
.GetFirstAndLastEPGDate();
722 CDateTime startDate
= dates
.first
;
723 CDateTime endDate
= dates
.second
;
724 const CDateTime currentDate
= CDateTime::GetUTCDateTime();
726 if (!startDate
.IsValid())
727 startDate
= currentDate
;
729 if (!endDate
.IsValid() || endDate
< startDate
)
732 // limit start to past days to display
733 const int iPastDays
= epgContainer
.GetPastDaysToDisplay();
734 const CDateTime
maxPastDate(currentDate
- CDateTimeSpan(iPastDays
, 0, 0, 0));
735 if (startDate
< maxPastDate
)
736 startDate
= maxPastDate
;
738 // limit end to future days to display
739 const int iFutureDays
= epgContainer
.GetFutureDaysToDisplay();
740 const CDateTime
maxFutureDate(currentDate
+ CDateTimeSpan(iFutureDays
, 0, 0, 0));
741 if (endDate
> maxFutureDate
)
742 endDate
= maxFutureDate
;
744 std::unique_ptr
<CFileItemList
> channels(new CFileItemList
);
745 const std::vector
<std::shared_ptr
<CPVRChannelGroupMember
>> groupMembers
=
746 group
->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE
);
748 for (const auto& groupMember
: groupMembers
)
750 channels
->Add(std::make_shared
<CFileItem
>(groupMember
));
754 channels
->Sort(m_guiState
->GetSortMethod());
756 epgGridContainer
->SetTimelineItems(channels
, startDate
, endDate
);
759 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
760 m_cachedChannelGroup
= group
;
768 bool CGUIWindowPVRGuideBase::GotoBegin()
770 GetGridControl()->GoToBegin();
774 bool CGUIWindowPVRGuideBase::GotoEnd()
776 GetGridControl()->GoToEnd();
780 bool CGUIWindowPVRGuideBase::GotoCurrentProgramme()
782 const CPVRManager
& mgr
= CServiceBroker::GetPVRManager();
783 std::shared_ptr
<CPVRChannel
> channel
= mgr
.PlaybackState()->GetPlayingChannel();
787 const std::shared_ptr
<const CPVREpgInfoTag
> playingTag
=
788 mgr
.PlaybackState()->GetPlayingEpgTag();
790 channel
= mgr
.ChannelGroups()->GetChannelForEpgTag(playingTag
);
794 GetGridControl()->GoToDate(
795 mgr
.PlaybackState()->GetPlaybackTime(channel
->ClientID(), channel
->UniqueID()));
797 GetGridControl()->GoToNow();
802 bool CGUIWindowPVRGuideBase::OpenDateSelectionDialog()
804 bool bReturn
= false;
806 KODI::TIME::SystemTime date
;
807 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
808 epgGridContainer
->GetSelectedDate().GetAsSystemTime(date
);
810 if (CGUIDialogNumeric::ShowAndGetDate(date
, g_localizeStrings
.Get(19288))) /* Go to date */
812 epgGridContainer
->GoToDate(CDateTime(date
));
819 bool CGUIWindowPVRGuideBase::Go12HoursBack()
821 return GotoDate(-12);
824 bool CGUIWindowPVRGuideBase::Go12HoursForward()
826 return GotoDate(+12);
829 bool CGUIWindowPVRGuideBase::GotoDate(int deltaHours
)
831 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
832 epgGridContainer
->GoToDate(epgGridContainer
->GetSelectedDate() +
833 CDateTimeSpan(0, deltaHours
, 0, 0));
837 bool CGUIWindowPVRGuideBase::GotoFirstChannel()
839 GetGridControl()->GoToFirstChannel();
843 bool CGUIWindowPVRGuideBase::GotoLastChannel()
845 GetGridControl()->GoToLastChannel();
849 bool CGUIWindowPVRGuideBase::GotoPlayingChannel()
851 const CPVRManager
& mgr
= CServiceBroker::GetPVRManager();
852 std::shared_ptr
<CPVRChannel
> channel
= mgr
.PlaybackState()->GetPlayingChannel();
856 const std::shared_ptr
<const CPVREpgInfoTag
> playingTag
=
857 mgr
.PlaybackState()->GetPlayingEpgTag();
859 channel
= mgr
.ChannelGroups()->GetChannelForEpgTag(playingTag
);
864 GetGridControl()->SetChannel(channel
);
870 void CGUIWindowPVRGuideBase::OnInputDone()
872 const CPVRChannelNumber channelNumber
= GetChannelNumber();
873 if (channelNumber
.IsValid())
875 GetGridControl()->SetChannel(channelNumber
);
879 void CGUIWindowPVRGuideBase::GetChannelNumbers(std::vector
<std::string
>& channelNumbers
)
881 const std::shared_ptr
<const CPVRChannelGroup
> group
= GetChannelGroup();
883 group
->GetChannelNumbers(channelNumbers
);
886 CPVRRefreshTimelineItemsThread::CPVRRefreshTimelineItemsThread(CGUIWindowPVRGuideBase
* pGuideWindow
)
887 : CThread("epg-grid-refresh-timeline-items"),
888 m_pGuideWindow(pGuideWindow
),
894 CPVRRefreshTimelineItemsThread::~CPVRRefreshTimelineItemsThread()
896 // Note: CThread dtor will also call StopThread(true), but if thread worker function exits that
897 // late, it might access member variables of this which are already destroyed. Thus, stop
898 // the thread worker here and synchronously, while all members of this are still alive.
902 void CPVRRefreshTimelineItemsThread::Stop()
905 m_ready
.Set(); // wake up the worker thread to let it exit
908 void CPVRRefreshTimelineItemsThread::DoRefresh(bool bWait
)
910 m_ready
.Set(); // wake up the worker thread
915 CGUIDialogBusy::WaitOnEvent(m_done
, 100, false);
919 void CPVRRefreshTimelineItemsThread::Process()
921 static const int BOOSTED_SLEEPS_THRESHOLD
= 4;
923 int iLastEpgItemsCount
= 0;
924 int iUpdatesWithoutChange
= 0;
930 if (m_pGuideWindow
->RefreshTimelineItems() && !m_bStop
)
932 CGUIMessage
m(GUI_MSG_REFRESH_LIST
, m_pGuideWindow
->GetID(), 0,
933 static_cast<int>(PVREvent::Epg
));
934 CServiceBroker::GetAppMessenger()->SendGUIMessage(m
);
942 // in order to fill the guide window asap, use a short update interval until we the
943 // same amount of epg events for BOOSTED_SLEEPS_THRESHOLD + 1 times in a row .
944 if (iUpdatesWithoutChange
< BOOSTED_SLEEPS_THRESHOLD
)
946 int iCurrentEpgItemsCount
= m_pGuideWindow
->CurrentDirectory().Size();
948 if (iCurrentEpgItemsCount
== iLastEpgItemsCount
)
949 iUpdatesWithoutChange
++;
951 iUpdatesWithoutChange
= 0; // reset
953 iLastEpgItemsCount
= iCurrentEpgItemsCount
;
955 m_ready
.Wait(1000ms
); // boosted update cycle
959 m_ready
.Wait(5000ms
); // normal update cycle
969 std::string
CGUIWindowPVRTVGuide::GetRootPath() const
971 return "pvr://guide/tv/";
974 std::string
CGUIWindowPVRRadioGuide::GetRootPath() const
976 return "pvr://guide/radio/";