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 "video/guilib/VideoPlayActionProcessor.h"
47 #include "view/GUIViewState.h"
55 using namespace KODI::MESSAGING
;
57 using namespace std::chrono_literals
;
59 CGUIWindowPVRGuideBase::CGUIWindowPVRGuideBase(bool bRadio
, int id
, const std::string
& xmlFile
)
60 : CGUIWindowPVRBase(bRadio
, id
, xmlFile
)
62 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Channels
>().RegisterChannelNumberInputHandler(this);
65 CGUIWindowPVRGuideBase::~CGUIWindowPVRGuideBase()
67 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Channels
>().DeregisterChannelNumberInputHandler(
70 m_bRefreshTimelineItems
= false;
71 m_bSyncRefreshTimelineItems
= false;
72 StopRefreshTimelineItemsThread();
75 CGUIEPGGridContainer
* CGUIWindowPVRGuideBase::GetGridControl()
77 return dynamic_cast<CGUIEPGGridContainer
*>(GetControl(m_viewControl
.GetCurrentControl()));
80 void CGUIWindowPVRGuideBase::InitEpgGridControl()
82 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
85 CPVRManager
& mgr
= CServiceBroker::GetPVRManager();
87 const std::shared_ptr
<CPVRChannel
> channel
= mgr
.ChannelGroups()->GetByPath(
88 mgr
.Get
<PVR::GUI::Channels
>().GetSelectedChannelPath(m_bRadio
));
92 m_bChannelSelectionRestored
= epgGridContainer
->SetChannel(channel
);
93 epgGridContainer
->JumpToDate(
94 mgr
.PlaybackState()->GetPlaybackTime(channel
->ClientID(), channel
->UniqueID()));
98 m_bChannelSelectionRestored
= false;
99 epgGridContainer
->JumpToNow();
102 if (!epgGridContainer
->HasData())
103 m_bSyncRefreshTimelineItems
= true; // force data update on first window open
106 StartRefreshTimelineItemsThread();
109 void CGUIWindowPVRGuideBase::ClearData()
112 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
113 m_cachedChannelGroup
.reset();
116 CGUIWindowPVRBase::ClearData();
119 void CGUIWindowPVRGuideBase::OnInitWindow()
122 m_viewControl
.SetCurrentView(m_guiState
->GetViewAsControl(), false);
124 if (InitChannelGroup()) // no channels -> lazy init
125 InitEpgGridControl();
127 CGUIWindowPVRBase::OnInitWindow();
130 void CGUIWindowPVRGuideBase::OnDeinitWindow(int nextWindowID
)
132 StopRefreshTimelineItemsThread();
134 m_bChannelSelectionRestored
= false;
137 CServiceBroker::GetGUI()->GetWindowManager().GetDialog(WINDOW_DIALOG_PVR_GUIDE_CONTROLS
);
138 if (dialog
&& dialog
->IsDialogRunning())
143 CGUIWindowPVRBase::OnDeinitWindow(nextWindowID
);
146 void CGUIWindowPVRGuideBase::StartRefreshTimelineItemsThread()
148 StopRefreshTimelineItemsThread();
149 m_refreshTimelineItemsThread
= std::make_unique
<CPVRRefreshTimelineItemsThread
>(this);
150 m_refreshTimelineItemsThread
->Create();
153 void CGUIWindowPVRGuideBase::StopRefreshTimelineItemsThread()
155 if (m_refreshTimelineItemsThread
)
156 m_refreshTimelineItemsThread
->Stop();
159 void CGUIWindowPVRGuideBase::NotifyEvent(const PVREvent
& event
)
161 if (event
== PVREvent::Epg
|| event
== PVREvent::EpgContainer
||
162 event
== PVREvent::ChannelGroupInvalidated
|| event
== PVREvent::ChannelGroup
)
164 m_bRefreshTimelineItems
= true;
165 // no base class call => do async refresh
168 else if (event
== PVREvent::ChannelPlaybackStopped
)
170 if (m_guiState
&& m_guiState
->GetSortMethod().sortBy
== SortByLastPlayed
)
172 // set dirty to force sync refresh
173 m_bSyncRefreshTimelineItems
= true;
177 // do sync refresh if dirty
178 CGUIWindowPVRBase::NotifyEvent(event
);
181 void CGUIWindowPVRGuideBase::SetInvalid()
183 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
184 if (epgGridContainer
)
185 epgGridContainer
->SetInvalid();
187 CGUIWindowPVRBase::SetInvalid();
190 void CGUIWindowPVRGuideBase::GetContextButtons(int itemNumber
, CContextButtons
& buttons
)
192 CGUIWindowPVRBase::GetContextButtons(itemNumber
, buttons
);
194 buttons
.Add(CONTEXT_BUTTON_NAVIGATE
, 19326); // Navigate...
197 void CGUIWindowPVRGuideBase::UpdateSelectedItemPath()
199 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
200 if (epgGridContainer
)
202 const std::shared_ptr
<const CPVRChannelGroupMember
> groupMember
=
203 epgGridContainer
->GetSelectedChannelGroupMember();
205 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Channels
>().SetSelectedChannelPath(
206 m_bRadio
, groupMember
->Path());
210 void CGUIWindowPVRGuideBase::UpdateButtons()
212 CGUIWindowPVRBase::UpdateButtons();
214 SET_CONTROL_LABEL(CONTROL_LABEL_HEADER1
, g_localizeStrings
.Get(19032));
216 const std::shared_ptr
<const CPVRChannelGroup
> group
= GetChannelGroup();
217 SET_CONTROL_LABEL(CONTROL_LABEL_HEADER2
, group
? group
->GroupName() : "");
220 bool CGUIWindowPVRGuideBase::Update(const std::string
& strDirectory
,
221 bool updateFilterPath
/* = true */)
225 // Prevent concurrent updates. Instead, let the timeline items refresh thread pick it up later.
226 m_bRefreshTimelineItems
= true;
230 bool bReturn
= CGUIWindowPVRBase::Update(strDirectory
, updateFilterPath
);
232 if (bReturn
&& !m_bChannelSelectionRestored
)
234 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
235 if (epgGridContainer
)
236 m_bChannelSelectionRestored
= epgGridContainer
->SetChannel(
237 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Channels
>().GetSelectedChannelPath(
244 bool CGUIWindowPVRGuideBase::GetDirectory(const std::string
& strDirectory
, CFileItemList
& items
)
247 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
249 if (m_cachedChannelGroup
&& *m_cachedChannelGroup
!= *GetChannelGroup())
251 // channel group change and not very first open of this window. force immediate update.
252 m_bSyncRefreshTimelineItems
= true;
256 if (m_bSyncRefreshTimelineItems
)
257 m_refreshTimelineItemsThread
->DoRefresh(true);
259 const CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
260 if (epgGridContainer
)
262 const std::unique_ptr
<CFileItemList
> newTimeline
= GetGridControl()->GetCurrentTimeLineItems();
263 items
.RemoveDiscCache(GetID());
264 items
.Assign(*newTimeline
, false);
270 void CGUIWindowPVRGuideBase::FormatAndSort(CFileItemList
& items
)
272 // Speedup: Nothing to do here as sorting was already done in RefreshTimelineItems
276 CFileItemPtr
CGUIWindowPVRGuideBase::GetCurrentListItem(int offset
/*= 0*/)
278 const CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
279 if (epgGridContainer
)
280 return epgGridContainer
->GetSelectedGridItem(offset
);
285 int CGUIWindowPVRGuideBase::GetCurrentListItemIndex(const std::shared_ptr
<const CFileItem
>& item
)
287 return item
? item
->GetProperty("TimelineIndex").asInteger32() : -1;
290 bool CGUIWindowPVRGuideBase::ShouldNavigateToGridContainer(int iAction
)
292 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
293 CGUIControl
* control
= GetControl(CONTROL_LSTCHANNELGROUPS
);
294 if (epgGridContainer
&& control
&& GetFocusedControlID() == control
->GetID())
296 int iNavigationId
= control
->GetAction(iAction
).GetNavigation();
297 if (iNavigationId
> 0)
299 control
= epgGridContainer
;
301 this) // navigation target could be the grid control or one of its parent controls.
303 if (iNavigationId
== control
->GetID())
305 // channel group selector control's target for the action is the grid control
308 control
= control
->GetParentControl();
315 bool CGUIWindowPVRGuideBase::OnAction(const CAction
& action
)
317 switch (action
.GetID())
320 case ACTION_MOVE_DOWN
:
321 case ACTION_MOVE_LEFT
:
322 case ACTION_MOVE_RIGHT
:
324 // Check whether grid container is configured as channel group selector's navigation target for the given action.
325 if (ShouldNavigateToGridContainer(action
.GetID()))
327 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
328 if (epgGridContainer
)
330 CGUIWindowPVRBase::OnAction(action
);
332 switch (action
.GetID())
335 epgGridContainer
->GoToBottom();
337 case ACTION_MOVE_DOWN
:
338 epgGridContainer
->GoToTop();
340 case ACTION_MOVE_LEFT
:
341 epgGridContainer
->GoToMostRight();
343 case ACTION_MOVE_RIGHT
:
344 epgGridContainer
->GoToMostLeft();
354 if (GetCurrentDigitCount() == 0)
356 // single zero input is handled by epg grid container
359 // fall-thru is intended
370 AppendChannelNumberCharacter(static_cast<char>(action
.GetID() - REMOTE_0
) + '0');
373 case ACTION_CHANNEL_NUMBER_SEP
:
374 AppendChannelNumberCharacter(CPVRChannelNumber::SEPARATOR
);
378 return CGUIWindowPVRBase::OnAction(action
);
381 void CGUIWindowPVRGuideBase::RefreshView(CGUIMessage
& message
, bool bInitGridControl
)
383 CGUIWindowPVRBase::OnMessage(message
);
385 // force grid data update
386 m_bSyncRefreshTimelineItems
= true;
388 if (bInitGridControl
)
389 InitEpgGridControl();
394 bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage
& message
)
396 bool bReturn
= false;
397 switch (message
.GetMessage())
399 case GUI_MSG_WINDOW_INIT
:
401 const CPVRChannelsPath
path(message
.GetStringParam(0));
402 if (path
.IsValid() && path
.IsChannelGroup())
404 // if a path to a channel group is given we must init
405 // that group instead of last played/selected group
406 SetChannelGroupPath(message
.GetStringParam(0));
411 case GUI_MSG_ITEM_SELECTED
:
412 message
.SetParam1(GetCurrentListItemIndex(GetCurrentListItem()));
416 case GUI_MSG_CLICKED
:
418 if (message
.GetSenderId() == m_viewControl
.GetCurrentControl())
420 if (message
.GetParam1() == ACTION_SELECT_ITEM
||
421 message
.GetParam1() == ACTION_MOUSE_LEFT_CLICK
)
423 // If direct channel number input is active, select the entered channel.
424 if (CServiceBroker::GetPVRManager()
425 .Get
<PVR::GUI::Channels
>()
426 .GetChannelNumberInputHandler()
427 .CheckInputAndExecuteAction())
434 const std::shared_ptr
<CFileItem
> pItem
= GetCurrentListItem();
437 switch (message
.GetParam1())
439 case ACTION_SELECT_ITEM
:
440 case ACTION_MOUSE_LEFT_CLICK
:
441 switch (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
442 CSettings::SETTING_EPG_SELECTACTION
))
444 case EPG_SELECT_ACTION_CONTEXT_MENU
:
445 OnPopupMenu(GetCurrentListItemIndex(pItem
));
448 case EPG_SELECT_ACTION_SWITCH
:
449 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().SwitchToChannel(*pItem
);
452 case EPG_SELECT_ACTION_PLAY_RECORDING
:
454 const std::shared_ptr
<CPVRRecording
> recording
{CPVRItem(pItem
).GetRecording()};
457 KODI::VIDEO::GUILIB::CVideoPlayActionProcessor proc
{
458 std::make_shared
<CFileItem
>(recording
)};
459 proc
.ProcessDefaultAction();
464 case EPG_SELECT_ACTION_INFO
:
465 CServiceBroker::GetPVRManager().Get
<PVR::GUI::EPG
>().ShowEPGInfo(*pItem
);
468 case EPG_SELECT_ACTION_RECORD
:
469 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Timers
>().ToggleTimer(*pItem
);
472 case EPG_SELECT_ACTION_SMART_SELECT
:
474 const std::shared_ptr
<const CPVREpgInfoTag
> tag(pItem
->GetEPGInfoTag());
477 const CDateTime
start(tag
->StartAsUTC());
478 const CDateTime
end(tag
->EndAsUTC());
479 const CDateTime
now(CDateTime::GetUTCDateTime());
481 if (start
<= now
&& now
<= end
)
484 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().SwitchToChannel(
487 else if (now
< start
)
490 if (CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(tag
))
491 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Timers
>().EditTimer(*pItem
);
494 bool bCanRecord
= true;
495 const std::shared_ptr
<const CPVRChannel
> channel
=
496 CPVRItem(pItem
).GetChannel();
498 bCanRecord
= channel
->CanRecord();
502 ? 19302 // "Do you want to record the selected programme or to switch to the current programme?"
503 : 19344; // "Do you want to set a reminder for the selected programme or to switch to the current programme?"
504 const int iNoButtonID
= bCanRecord
? 264 // No => "Record"
505 : 826; // "Set reminder"
507 HELPERS::DialogResponse ret
=
508 HELPERS::ShowYesNoDialogText(CVariant
{19096}, // "Smart select"
509 CVariant
{iTextID
}, CVariant
{iNoButtonID
},
510 CVariant
{19165}); // Yes => "Switch"
511 if (ret
== HELPERS::DialogResponse::CHOICE_NO
)
512 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Timers
>().AddTimer(*pItem
,
514 else if (ret
== HELPERS::DialogResponse::CHOICE_YES
)
515 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().SwitchToChannel(
522 const std::shared_ptr
<CPVRRecording
> recording
{
523 CPVRItem(pItem
).GetRecording()};
526 KODI::VIDEO::GUILIB::CVideoPlayActionProcessor proc
{
527 std::make_shared
<CFileItem
>(recording
)};
528 proc
.ProcessDefaultAction();
530 else if (tag
->IsPlayable())
531 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().PlayEpgTag(
534 CServiceBroker::GetPVRManager().Get
<PVR::GUI::EPG
>().ShowEPGInfo(*pItem
);
542 case ACTION_SHOW_INFO
:
543 CServiceBroker::GetPVRManager().Get
<PVR::GUI::EPG
>().ShowEPGInfo(*pItem
);
546 case ACTION_PLAYER_PLAY
:
547 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Playback
>().SwitchToChannel(*pItem
);
551 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Timers
>().ToggleTimer(*pItem
);
554 case ACTION_PVR_SHOW_TIMER_RULE
:
555 CServiceBroker::GetPVRManager().Get
<PVR::GUI::Timers
>().AddTimerRule(*pItem
, true,
559 case ACTION_CONTEXT_MENU
:
560 case ACTION_MOUSE_RIGHT_CLICK
:
561 OnPopupMenu(GetCurrentListItemIndex(pItem
));
567 else if (message
.GetSenderId() == CONTROL_BTNVIEWASICONS
||
568 message
.GetSenderId() == CONTROL_BTNSORTBY
||
569 message
.GetSenderId() == CONTROL_BTNSORTASC
)
571 RefreshView(message
, false);
576 case GUI_MSG_CHANGE_SORT_DIRECTION
:
577 case GUI_MSG_CHANGE_SORT_METHOD
:
578 case GUI_MSG_CHANGE_VIEW_MODE
:
580 RefreshView(message
, message
.GetMessage() == GUI_MSG_CHANGE_VIEW_MODE
);
584 case GUI_MSG_REFRESH_LIST
:
586 switch (static_cast<PVREvent
>(message
.GetParam1()))
588 case PVREvent::ManagerStarted
:
589 if (InitChannelGroup())
590 InitEpgGridControl();
593 case PVREvent::ChannelGroup
:
594 case PVREvent::ChannelGroupInvalidated
:
595 case PVREvent::ClientsInvalidated
:
596 case PVREvent::ChannelPlaybackStopped
:
598 case PVREvent::EpgContainer
:
599 if (InitChannelGroup())
603 case PVREvent::Timers
:
604 case PVREvent::TimersInvalidated
:
613 case GUI_MSG_SYSTEM_WAKE
:
614 GotoCurrentProgramme();
619 return bReturn
|| CGUIWindowPVRBase::OnMessage(message
);
622 bool CGUIWindowPVRGuideBase::OnContextButton(int itemNumber
, CONTEXT_BUTTON button
)
624 if (OnContextButtonNavigate(button
))
627 if (itemNumber
< 0 || itemNumber
>= m_vecItems
->Size())
630 return CGUIMediaWindow::OnContextButton(itemNumber
, button
);
637 class CContextMenuFunctions
: public CContextButtons
640 explicit CContextMenuFunctions(A
* instance
) : m_instance(instance
) {}
642 void Add(bool (A::*function
)(), unsigned int resId
)
644 CContextButtons::Add(static_cast<unsigned int>(size()), resId
);
645 m_functions
.emplace_back(std::bind(function
, m_instance
));
650 if (idx
< 0 || idx
>= static_cast<int>(m_functions
.size()))
653 return m_functions
[idx
]();
657 A
* m_instance
= nullptr;
658 std::vector
<std::function
<bool()>> m_functions
;
661 } // unnamed namespace
663 bool CGUIWindowPVRGuideBase::OnContextButtonNavigate(CONTEXT_BUTTON button
)
665 bool bReturn
= false;
667 if (button
== CONTEXT_BUTTON_NAVIGATE
)
669 if (g_SkinInfo
->HasSkinFile("DialogPVRGuideControls.xml"))
671 // use controls dialog
673 CServiceBroker::GetGUI()->GetWindowManager().GetDialog(WINDOW_DIALOG_PVR_GUIDE_CONTROLS
);
674 if (dialog
&& !dialog
->IsDialogRunning())
682 CContextMenuFunctions
<CGUIWindowPVRGuideBase
> buttons(this);
683 buttons
.Add(&CGUIWindowPVRGuideBase::GotoBegin
, 19063); // First programme
684 buttons
.Add(&CGUIWindowPVRGuideBase::Go12HoursBack
, 19317); // 12 hours back
685 buttons
.Add(&CGUIWindowPVRGuideBase::GotoCurrentProgramme
, 19070); // Current programme
686 buttons
.Add(&CGUIWindowPVRGuideBase::Go12HoursForward
, 19318); // 12 hours forward
687 buttons
.Add(&CGUIWindowPVRGuideBase::GotoEnd
, 19064); // Last programme
688 buttons
.Add(&CGUIWindowPVRGuideBase::OpenDateSelectionDialog
, 19288); // Date selector
689 buttons
.Add(&CGUIWindowPVRGuideBase::GotoFirstChannel
, 19322); // First channel
690 if (CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingTV() ||
691 CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingRadio() ||
692 CServiceBroker::GetPVRManager().PlaybackState()->IsPlayingEpgTag())
693 buttons
.Add(&CGUIWindowPVRGuideBase::GotoPlayingChannel
, 19323); // Playing channel
694 buttons
.Add(&CGUIWindowPVRGuideBase::GotoLastChannel
, 19324); // Last channel
695 buttons
.Add(&CGUIWindowPVRBase::ActivatePreviousChannelGroup
, 19319); // Previous group
696 buttons
.Add(&CGUIWindowPVRBase::ActivateNextChannelGroup
, 19320); // Next group
697 buttons
.Add(&CGUIWindowPVRBase::OpenChannelGroupSelectionDialog
, 19321); // Group selector
700 int lastButtonIdx
= 2; // initially select "Current programme"
702 // loop until canceled
703 while (buttonIdx
>= 0)
705 buttonIdx
= CGUIDialogContextMenu::Show(buttons
, lastButtonIdx
);
706 lastButtonIdx
= buttonIdx
;
707 buttons
.Call(buttonIdx
);
716 bool CGUIWindowPVRGuideBase::RefreshTimelineItems()
718 if (m_bRefreshTimelineItems
|| m_bSyncRefreshTimelineItems
)
720 m_bRefreshTimelineItems
= false;
721 m_bSyncRefreshTimelineItems
= false;
723 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
724 if (epgGridContainer
)
726 const std::shared_ptr
<CPVRChannelGroup
> group(GetChannelGroup());
730 CPVREpgContainer
& epgContainer
= CServiceBroker::GetPVRManager().EpgContainer();
732 const std::pair
<CDateTime
, CDateTime
> dates
= epgContainer
.GetFirstAndLastEPGDate();
733 CDateTime startDate
= dates
.first
;
734 CDateTime endDate
= dates
.second
;
735 const CDateTime currentDate
= CDateTime::GetUTCDateTime();
737 if (!startDate
.IsValid())
738 startDate
= currentDate
;
740 if (!endDate
.IsValid() || endDate
< startDate
)
743 // limit start to past days to display
744 const int iPastDays
= epgContainer
.GetPastDaysToDisplay();
745 const CDateTime
maxPastDate(currentDate
- CDateTimeSpan(iPastDays
, 0, 0, 0));
746 if (startDate
< maxPastDate
)
747 startDate
= maxPastDate
;
749 // limit end to future days to display
750 const int iFutureDays
= epgContainer
.GetFutureDaysToDisplay();
751 const CDateTime
maxFutureDate(currentDate
+ CDateTimeSpan(iFutureDays
, 0, 0, 0));
752 if (endDate
> maxFutureDate
)
753 endDate
= maxFutureDate
;
755 std::unique_ptr
<CFileItemList
> channels(new CFileItemList
);
756 const std::vector
<std::shared_ptr
<CPVRChannelGroupMember
>> groupMembers
=
757 group
->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE
);
759 for (const auto& groupMember
: groupMembers
)
761 channels
->Add(std::make_shared
<CFileItem
>(groupMember
));
765 channels
->Sort(m_guiState
->GetSortMethod());
767 epgGridContainer
->SetTimelineItems(channels
, startDate
, endDate
);
770 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
771 m_cachedChannelGroup
= group
;
779 bool CGUIWindowPVRGuideBase::GotoBegin()
781 GetGridControl()->GoToBegin();
785 bool CGUIWindowPVRGuideBase::GotoEnd()
787 GetGridControl()->GoToEnd();
791 bool CGUIWindowPVRGuideBase::GotoCurrentProgramme()
793 const CPVRManager
& mgr
= CServiceBroker::GetPVRManager();
794 std::shared_ptr
<CPVRChannel
> channel
= mgr
.PlaybackState()->GetPlayingChannel();
798 const std::shared_ptr
<const CPVREpgInfoTag
> playingTag
=
799 mgr
.PlaybackState()->GetPlayingEpgTag();
801 channel
= mgr
.ChannelGroups()->GetChannelForEpgTag(playingTag
);
805 GetGridControl()->GoToDate(
806 mgr
.PlaybackState()->GetPlaybackTime(channel
->ClientID(), channel
->UniqueID()));
808 GetGridControl()->GoToNow();
813 bool CGUIWindowPVRGuideBase::OpenDateSelectionDialog()
815 bool bReturn
= false;
817 KODI::TIME::SystemTime date
;
818 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
819 epgGridContainer
->GetSelectedDate().GetAsSystemTime(date
);
821 if (CGUIDialogNumeric::ShowAndGetDate(date
, g_localizeStrings
.Get(19288))) /* Go to date */
823 epgGridContainer
->GoToDate(CDateTime(date
));
830 bool CGUIWindowPVRGuideBase::Go12HoursBack()
832 return GotoDate(-12);
835 bool CGUIWindowPVRGuideBase::Go12HoursForward()
837 return GotoDate(+12);
840 bool CGUIWindowPVRGuideBase::GotoDate(int deltaHours
)
842 CGUIEPGGridContainer
* epgGridContainer
= GetGridControl();
843 epgGridContainer
->GoToDate(epgGridContainer
->GetSelectedDate() +
844 CDateTimeSpan(0, deltaHours
, 0, 0));
848 bool CGUIWindowPVRGuideBase::GotoFirstChannel()
850 GetGridControl()->GoToFirstChannel();
854 bool CGUIWindowPVRGuideBase::GotoLastChannel()
856 GetGridControl()->GoToLastChannel();
860 bool CGUIWindowPVRGuideBase::GotoPlayingChannel()
862 const CPVRManager
& mgr
= CServiceBroker::GetPVRManager();
863 std::shared_ptr
<CPVRChannel
> channel
= mgr
.PlaybackState()->GetPlayingChannel();
867 const std::shared_ptr
<const CPVREpgInfoTag
> playingTag
=
868 mgr
.PlaybackState()->GetPlayingEpgTag();
870 channel
= mgr
.ChannelGroups()->GetChannelForEpgTag(playingTag
);
875 GetGridControl()->SetChannel(channel
);
881 void CGUIWindowPVRGuideBase::OnInputDone()
883 const CPVRChannelNumber channelNumber
= GetChannelNumber();
884 if (channelNumber
.IsValid())
886 GetGridControl()->SetChannel(channelNumber
);
890 void CGUIWindowPVRGuideBase::GetChannelNumbers(std::vector
<std::string
>& channelNumbers
)
892 const std::shared_ptr
<const CPVRChannelGroup
> group
= GetChannelGroup();
894 group
->GetChannelNumbers(channelNumbers
);
897 CPVRRefreshTimelineItemsThread::CPVRRefreshTimelineItemsThread(CGUIWindowPVRGuideBase
* pGuideWindow
)
898 : CThread("epg-grid-refresh-timeline-items"),
899 m_pGuideWindow(pGuideWindow
),
905 CPVRRefreshTimelineItemsThread::~CPVRRefreshTimelineItemsThread()
907 // Note: CThread dtor will also call StopThread(true), but if thread worker function exits that
908 // late, it might access member variables of this which are already destroyed. Thus, stop
909 // the thread worker here and synchronously, while all members of this are still alive.
913 void CPVRRefreshTimelineItemsThread::Stop()
916 m_ready
.Set(); // wake up the worker thread to let it exit
919 void CPVRRefreshTimelineItemsThread::DoRefresh(bool bWait
)
921 m_ready
.Set(); // wake up the worker thread
926 CGUIDialogBusy::WaitOnEvent(m_done
, 100, false);
930 void CPVRRefreshTimelineItemsThread::Process()
932 static const int BOOSTED_SLEEPS_THRESHOLD
= 4;
934 int iLastEpgItemsCount
= 0;
935 int iUpdatesWithoutChange
= 0;
941 if (m_pGuideWindow
->RefreshTimelineItems() && !m_bStop
)
943 CGUIMessage
m(GUI_MSG_REFRESH_LIST
, m_pGuideWindow
->GetID(), 0,
944 static_cast<int>(PVREvent::Epg
));
945 CServiceBroker::GetAppMessenger()->SendGUIMessage(m
);
953 // in order to fill the guide window asap, use a short update interval until we the
954 // same amount of epg events for BOOSTED_SLEEPS_THRESHOLD + 1 times in a row .
955 if (iUpdatesWithoutChange
< BOOSTED_SLEEPS_THRESHOLD
)
957 int iCurrentEpgItemsCount
= m_pGuideWindow
->CurrentDirectory().Size();
959 if (iCurrentEpgItemsCount
== iLastEpgItemsCount
)
960 iUpdatesWithoutChange
++;
962 iUpdatesWithoutChange
= 0; // reset
964 iLastEpgItemsCount
= iCurrentEpgItemsCount
;
966 m_ready
.Wait(1000ms
); // boosted update cycle
970 m_ready
.Wait(5000ms
); // normal update cycle
980 std::string
CGUIWindowPVRTVGuide::GetRootPath() const
982 return "pvr://guide/tv/";
985 std::string
CGUIWindowPVRRadioGuide::GetRootPath() const
987 return "pvr://guide/radio/";