[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / pvr / guilib / GUIEPGGridContainerModel.cpp
blobdf6f7e41cd9b9c2aa245e18add5b9272606c02b7
1 /*
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.
7 */
9 #include "GUIEPGGridContainerModel.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "ServiceBroker.h"
14 #include "pvr/PVRManager.h"
15 #include "pvr/channels/PVRChannel.h"
16 #include "pvr/epg/Epg.h"
17 #include "pvr/epg/EpgChannelData.h"
18 #include "pvr/epg/EpgContainer.h"
19 #include "pvr/epg/EpgInfoTag.h"
20 #include "utils/Variant.h"
21 #include "utils/log.h"
23 #include <algorithm>
24 #include <cmath>
25 #include <iterator>
26 #include <memory>
27 #include <vector>
29 using namespace PVR;
31 static const unsigned int GRID_START_PADDING = 30; // minutes
33 void CGUIEPGGridContainerModel::SetInvalid()
35 for (const auto& gridItem : m_gridIndex)
36 gridItem.second.item->SetInvalid();
37 for (const auto& channel : m_channelItems)
38 channel->SetInvalid();
39 for (const auto& ruler : m_rulerItems)
40 ruler->SetInvalid();
43 std::shared_ptr<CFileItem> CGUIEPGGridContainerModel::CreateGapItem(int iChannel) const
45 const std::shared_ptr<const CPVRChannel> channel =
46 m_channelItems[iChannel]->GetPVRChannelInfoTag();
47 const std::shared_ptr<CPVREpgInfoTag> gapTag = channel->CreateEPGGapTag(m_gridStart, m_gridEnd);
48 return std::make_shared<CFileItem>(gapTag);
51 std::vector<std::shared_ptr<CPVREpgInfoTag>> CGUIEPGGridContainerModel::GetEPGTimeline(
52 int iChannel, const CDateTime& minEventEnd, const CDateTime& maxEventStart) const
54 CDateTime min = minEventEnd - CDateTimeSpan(0, 0, MINSPERBLOCK, 0) + CDateTimeSpan(0, 0, 0, 1);
55 CDateTime max = maxEventStart + CDateTimeSpan(0, 0, MINSPERBLOCK, 0);
57 if (min < m_gridStart)
58 min = m_gridStart;
60 if (max > m_gridEnd)
61 max = m_gridEnd;
63 return m_channelItems[iChannel]->GetPVRChannelInfoTag()->GetEPGTimeline(m_gridStart, m_gridEnd,
64 min, max);
67 void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr<CFileItemList>& items,
68 const CDateTime& gridStart,
69 const CDateTime& gridEnd,
70 int iFirstChannel,
71 int iChannelsPerPage,
72 int iFirstBlock,
73 int iBlocksPerPage,
74 int iRulerUnit,
75 float fBlockSize)
77 if (!m_channelItems.empty())
79 CLog::LogF(LOGERROR, "Already initialized!");
80 return;
83 m_fBlockSize = fBlockSize;
85 ////////////////////////////////////////////////////////////////////////
86 // Create channel items
87 std::copy(items->cbegin(), items->cend(), std::back_inserter(m_channelItems));
89 /* check for invalid start and end time */
90 if (gridStart >= gridEnd)
92 // default to start "now minus GRID_START_PADDING minutes" and end "start plus one page".
93 m_gridStart = CDateTime::GetUTCDateTime() - CDateTimeSpan(0, 0, GetGridStartPadding(), 0);
94 m_gridEnd = m_gridStart + CDateTimeSpan(0, 0, iBlocksPerPage * MINSPERBLOCK, 0);
96 else if (gridStart >
97 (CDateTime::GetUTCDateTime() - CDateTimeSpan(0, 0, GetGridStartPadding(), 0)))
99 // adjust to start "now minus GRID_START_PADDING minutes".
100 m_gridStart = CDateTime::GetUTCDateTime() - CDateTimeSpan(0, 0, GetGridStartPadding(), 0);
101 m_gridEnd = gridEnd;
103 else
105 m_gridStart = gridStart;
106 m_gridEnd = gridEnd;
109 // roundup
110 m_gridStart = CDateTime(m_gridStart.GetYear(), m_gridStart.GetMonth(), m_gridStart.GetDay(),
111 m_gridStart.GetHour(), m_gridStart.GetMinute() >= 30 ? 30 : 0, 0);
112 m_gridEnd = CDateTime(m_gridEnd.GetYear(), m_gridEnd.GetMonth(), m_gridEnd.GetDay(),
113 m_gridEnd.GetHour(), m_gridEnd.GetMinute() >= 30 ? 30 : 0, 0);
115 m_blocks = GetBlock(m_gridEnd) + 1;
117 const int iBlocksLastPage = m_blocks % iBlocksPerPage;
118 if (iBlocksLastPage > 0)
120 m_gridEnd += CDateTimeSpan(0, 0, (iBlocksPerPage - iBlocksLastPage) * MINSPERBLOCK, 0);
121 m_blocks += (iBlocksPerPage - iBlocksLastPage);
124 ////////////////////////////////////////////////////////////////////////
125 // Create ruler items
126 CDateTime ruler;
127 ruler.SetFromUTCDateTime(m_gridStart);
128 CDateTime rulerEnd;
129 rulerEnd.SetFromUTCDateTime(m_gridEnd);
130 CFileItemPtr rulerItem(new CFileItem(ruler.GetAsLocalizedDate(true)));
131 rulerItem->SetProperty("DateLabel", true);
132 m_rulerItems.emplace_back(rulerItem);
134 const CDateTimeSpan unit(0, 0, iRulerUnit * MINSPERBLOCK, 0);
135 for (; ruler < rulerEnd; ruler += unit)
137 rulerItem = std::make_shared<CFileItem>(ruler.GetAsLocalizedTime("", false));
138 rulerItem->SetLabel2(ruler.GetAsLocalizedDate(true));
139 m_rulerItems.emplace_back(rulerItem);
142 m_firstActiveChannel = iFirstChannel;
143 m_lastActiveChannel = iFirstChannel + iChannelsPerPage - 1;
144 m_firstActiveBlock = iFirstBlock;
145 m_lastActiveBlock = iFirstBlock + iBlocksPerPage - 1;
148 std::shared_ptr<CFileItem> CGUIEPGGridContainerModel::CreateEpgTags(int iChannel, int iBlock) const
150 std::shared_ptr<CFileItem> result;
152 const int firstBlock = iBlock < m_firstActiveBlock ? iBlock : m_firstActiveBlock;
153 const int lastBlock = iBlock > m_lastActiveBlock ? iBlock : m_lastActiveBlock;
155 const auto tags =
156 GetEPGTimeline(iChannel, GetStartTimeForBlock(firstBlock), GetStartTimeForBlock(lastBlock));
158 const int firstResultBlock = GetFirstEventBlock(tags.front());
159 const int lastResultBlock = GetLastEventBlock(tags.back());
160 if (firstResultBlock > lastResultBlock)
161 return result;
163 auto it = m_epgItems.insert({iChannel, EpgTags()}).first;
164 EpgTags& epgTags = (*it).second;
166 epgTags.firstBlock = firstResultBlock;
167 epgTags.lastBlock = lastResultBlock;
169 for (const auto& tag : tags)
171 if (GetFirstEventBlock(tag) > GetLastEventBlock(tag))
172 continue;
174 const std::shared_ptr<CFileItem> item = std::make_shared<CFileItem>(tag);
175 if (!result && IsEventMemberOfBlock(tag, iBlock))
176 result = item;
178 epgTags.tags.emplace_back(item);
181 return result;
184 std::shared_ptr<CFileItem> CGUIEPGGridContainerModel::GetEpgTags(EpgTagsMap::iterator& itEpg,
185 int iChannel,
186 int iBlock) const
188 std::shared_ptr<CFileItem> result;
190 EpgTags& epgTags = (*itEpg).second;
192 if (iBlock < epgTags.firstBlock)
194 result = GetEpgTagsBefore(epgTags, iChannel, iBlock);
196 else if (iBlock > epgTags.lastBlock)
198 result = GetEpgTagsAfter(epgTags, iChannel, iBlock);
200 else
202 const auto it =
203 std::find_if(epgTags.tags.cbegin(), epgTags.tags.cend(), [this, iBlock](const auto& item) {
204 return IsEventMemberOfBlock(item->GetEPGInfoTag(), iBlock);
206 if (it != epgTags.tags.cend())
207 result = (*it);
210 return result;
213 std::shared_ptr<CFileItem> CGUIEPGGridContainerModel::GetEpgTagsBefore(EpgTags& epgTags,
214 int iChannel,
215 int iBlock) const
217 std::shared_ptr<CFileItem> result;
219 int lastBlock = epgTags.firstBlock - 1;
220 if (lastBlock < 0)
221 lastBlock = 0;
223 const auto tags =
224 GetEPGTimeline(iChannel, GetStartTimeForBlock(iBlock), GetStartTimeForBlock(lastBlock));
226 if (epgTags.lastBlock == -1)
227 epgTags.lastBlock = lastBlock;
229 if (tags.empty())
231 epgTags.firstBlock = iBlock;
233 else
235 const int firstResultBlock = GetFirstEventBlock(tags.front());
236 const int lastResultBlock = GetLastEventBlock(tags.back());
237 if (firstResultBlock > lastResultBlock)
238 return result;
240 // insert before the existing tags
241 epgTags.firstBlock = firstResultBlock;
243 auto it = tags.crbegin();
244 if (!epgTags.tags.empty())
246 // ptr comp does not work for gap tags!
247 // if ((*it) == epgTags.tags.front()->GetEPGInfoTag())
249 const std::shared_ptr<const CPVREpgInfoTag> t = epgTags.tags.front()->GetEPGInfoTag();
250 if ((*it)->StartAsUTC() == t->StartAsUTC() && (*it)->EndAsUTC() == t->EndAsUTC())
252 if (!result && IsEventMemberOfBlock(*it, iBlock))
253 result = epgTags.tags.front();
255 ++it; // skip, because we already have that epg tag
259 for (; it != tags.crend(); ++it)
261 if (GetFirstEventBlock(*it) > GetLastEventBlock(*it))
262 continue;
264 const std::shared_ptr<CFileItem> item = std::make_shared<CFileItem>(*it);
265 if (!result && IsEventMemberOfBlock(*it, iBlock))
266 result = item;
268 epgTags.tags.insert(epgTags.tags.begin(), item);
272 return result;
275 std::shared_ptr<CFileItem> CGUIEPGGridContainerModel::GetEpgTagsAfter(EpgTags& epgTags,
276 int iChannel,
277 int iBlock) const
279 std::shared_ptr<CFileItem> result;
281 int firstBlock = epgTags.lastBlock + 1;
282 if (firstBlock >= GetLastBlock())
283 firstBlock = GetLastBlock();
285 const auto tags =
286 GetEPGTimeline(iChannel, GetStartTimeForBlock(firstBlock), GetStartTimeForBlock(iBlock));
288 if (epgTags.firstBlock == -1)
289 epgTags.firstBlock = firstBlock;
291 if (tags.empty())
293 epgTags.lastBlock = iBlock;
295 else
297 const int firstResultBlock = GetFirstEventBlock(tags.front());
298 const int lastResultBlock = GetLastEventBlock(tags.back());
299 if (firstResultBlock > lastResultBlock)
300 return result;
302 // append to the existing tags
303 epgTags.lastBlock = lastResultBlock;
305 auto it = tags.cbegin();
306 if (!epgTags.tags.empty())
308 // ptr comp does not work for gap tags!
309 // if ((*it) == epgTags.tags.back()->GetEPGInfoTag())
311 const std::shared_ptr<const CPVREpgInfoTag> t = epgTags.tags.back()->GetEPGInfoTag();
312 if ((*it)->StartAsUTC() == t->StartAsUTC() && (*it)->EndAsUTC() == t->EndAsUTC())
314 if (!result && IsEventMemberOfBlock(*it, iBlock))
315 result = epgTags.tags.back();
317 ++it; // skip, because we already have that epg tag
321 for (; it != tags.cend(); ++it)
323 if (GetFirstEventBlock(*it) > GetLastEventBlock(*it))
324 continue;
326 const std::shared_ptr<CFileItem> item = std::make_shared<CFileItem>(*it);
327 if (!result && IsEventMemberOfBlock(*it, iBlock))
328 result = item;
330 epgTags.tags.emplace_back(item);
334 return result;
337 std::shared_ptr<CFileItem> CGUIEPGGridContainerModel::GetItem(int iChannel, int iBlock) const
339 std::shared_ptr<CFileItem> result;
341 auto itEpg = m_epgItems.find(iChannel);
342 if (itEpg == m_epgItems.end())
344 result = CreateEpgTags(iChannel, iBlock);
346 else
348 result = GetEpgTags(itEpg, iChannel, iBlock);
351 if (!result)
353 // Must never happen. if it does, fix the root cause, don't tolerate nullptr!
354 CLog::LogF(LOGERROR, "EPG tag ({}, {}) not found!", iChannel, iBlock);
357 return result;
360 void CGUIEPGGridContainerModel::FindChannelAndBlockIndex(int channelUid,
361 unsigned int broadcastUid,
362 int eventOffset,
363 int& newChannelIndex,
364 int& newBlockIndex) const
366 newChannelIndex = INVALID_INDEX;
367 newBlockIndex = INVALID_INDEX;
369 // find the new channel index
370 int iCurrentChannel = 0;
371 for (const auto& channel : m_channelItems)
373 if (channel->GetPVRChannelInfoTag()->UniqueID() == channelUid)
375 newChannelIndex = iCurrentChannel;
377 // find the new block index
378 const std::shared_ptr<const CPVREpg> epg = channel->GetPVRChannelInfoTag()->GetEPG();
379 if (epg)
381 const std::shared_ptr<const CPVREpgInfoTag> tag = epg->GetTagByBroadcastId(broadcastUid);
382 if (tag)
383 newBlockIndex = GetFirstEventBlock(tag) + eventOffset;
385 break; // done
387 iCurrentChannel++;
391 GridItem* CGUIEPGGridContainerModel::GetGridItemPtr(int iChannel, int iBlock) const
393 auto it = m_gridIndex.find({iChannel, iBlock});
394 if (it == m_gridIndex.end())
396 const CDateTime startTime = GetStartTimeForBlock(iBlock);
397 if (startTime < m_gridStart || m_gridEnd < startTime)
399 CLog::LogF(LOGERROR, "Requested EPG tag ({}, {}) outside grid boundaries!", iChannel, iBlock);
400 return nullptr;
403 const std::shared_ptr<CFileItem> item = GetItem(iChannel, iBlock);
404 if (!item)
406 CLog::LogF(LOGERROR, "Got no EPG tag ({}, {})!", iChannel, iBlock);
407 return nullptr;
410 const std::shared_ptr<const CPVREpgInfoTag> epgTag = item->GetEPGInfoTag();
412 const int startBlock = GetFirstEventBlock(epgTag);
413 const int endBlock = GetLastEventBlock(epgTag);
415 //! @todo it seems that this should be done somewhere else. CFileItem ctor maybe.
416 item->SetProperty("GenreType", epgTag->GenreType());
418 const float fItemWidth = (endBlock - startBlock + 1) * m_fBlockSize;
419 it = m_gridIndex.insert({{iChannel, iBlock}, {item, fItemWidth, startBlock, endBlock}}).first;
422 return &(*it).second;
425 bool CGUIEPGGridContainerModel::IsSameGridItem(int iChannel, int iBlock1, int iBlock2) const
427 if (iBlock1 == iBlock2)
428 return true;
430 const GridItem* item1 = GetGridItemPtr(iChannel, iBlock1);
431 const GridItem* item2 = GetGridItemPtr(iChannel, iBlock2);
433 // compare the instances, not instance pointers, pointers are not unique.
434 return *item1 == *item2;
437 std::shared_ptr<CFileItem> CGUIEPGGridContainerModel::GetGridItem(int iChannel, int iBlock) const
439 return GetGridItemPtr(iChannel, iBlock)->item;
442 int CGUIEPGGridContainerModel::GetGridItemStartBlock(int iChannel, int iBlock) const
444 return GetGridItemPtr(iChannel, iBlock)->startBlock;
447 int CGUIEPGGridContainerModel::GetGridItemEndBlock(int iChannel, int iBlock) const
449 return GetGridItemPtr(iChannel, iBlock)->endBlock;
452 CDateTime CGUIEPGGridContainerModel::GetGridItemEndTime(int iChannel, int iBlock) const
454 return GetGridItemPtr(iChannel, iBlock)->item->GetEPGInfoTag()->EndAsUTC();
457 float CGUIEPGGridContainerModel::GetGridItemWidth(int iChannel, int iBlock) const
459 return GetGridItemPtr(iChannel, iBlock)->width;
462 float CGUIEPGGridContainerModel::GetGridItemOriginWidth(int iChannel, int iBlock) const
464 return GetGridItemPtr(iChannel, iBlock)->originWidth;
467 void CGUIEPGGridContainerModel::DecreaseGridItemWidth(int iChannel, int iBlock, float fSize)
469 auto it = m_gridIndex.find({iChannel, iBlock});
470 if (it != m_gridIndex.end() && (*it).second.width != ((*it).second.originWidth - fSize))
471 (*it).second.width = (*it).second.originWidth - fSize;
474 unsigned int CGUIEPGGridContainerModel::GetGridStartPadding() const
476 unsigned int iPastMinutes =
477 CServiceBroker::GetPVRManager().EpgContainer().GetPastDaysToDisplay() * 24 * 60;
479 if (iPastMinutes < GRID_START_PADDING)
480 return iPastMinutes;
482 return GRID_START_PADDING; // minutes
485 void CGUIEPGGridContainerModel::FreeChannelMemory(int keepStart, int keepEnd)
487 if (keepStart < keepEnd)
489 // remove before keepStart and after keepEnd
490 for (int i = 0; i < keepStart && i < ChannelItemsSize(); ++i)
491 m_channelItems[i]->FreeMemory();
492 for (int i = keepEnd + 1; i < ChannelItemsSize(); ++i)
493 m_channelItems[i]->FreeMemory();
495 else
497 // wrapping
498 for (int i = keepEnd + 1; i < keepStart && i < ChannelItemsSize(); ++i)
499 m_channelItems[i]->FreeMemory();
503 bool CGUIEPGGridContainerModel::FreeProgrammeMemory(int firstChannel,
504 int lastChannel,
505 int firstBlock,
506 int lastBlock)
508 const bool channelsChanged =
509 (firstChannel != m_firstActiveChannel || lastChannel != m_lastActiveChannel);
510 const bool blocksChanged = (firstBlock != m_firstActiveBlock || lastBlock != m_lastActiveBlock);
511 if (!channelsChanged && !blocksChanged)
512 return false;
514 // clear the grid. it will be recreated on-demand.
515 m_gridIndex.clear();
517 bool newChannels = false;
519 if (channelsChanged)
521 // purge epg tags for inactive channels
522 for (auto it = m_epgItems.begin(); it != m_epgItems.end();)
524 if ((*it).first < firstChannel || (*it).first > lastChannel)
526 it = m_epgItems.erase(it);
527 continue; // next channel
529 ++it;
532 newChannels = (firstChannel < m_firstActiveChannel) || (lastChannel > m_lastActiveChannel);
535 if (blocksChanged || newChannels)
537 // clear and refetch epg tags for active channels
538 const CDateTime maxEnd = GetStartTimeForBlock(firstBlock);
539 const CDateTime minStart = GetStartTimeForBlock(lastBlock);
540 std::vector<std::shared_ptr<CPVREpgInfoTag>> tags;
541 for (int i = firstChannel; i <= lastChannel; ++i)
543 auto it = m_epgItems.find(i);
544 if (it == m_epgItems.end())
545 it = m_epgItems.insert({i, EpgTags()}).first;
547 if (blocksChanged || i < m_firstActiveChannel || i > m_lastActiveChannel)
549 EpgTags& epgTags = (*it).second;
551 (*it).second.tags.clear();
553 tags = GetEPGTimeline(i, maxEnd, minStart);
554 const int firstResultBlock = GetFirstEventBlock(tags.front());
555 const int lastResultBlock = GetLastEventBlock(tags.back());
556 if (firstResultBlock > lastResultBlock)
557 continue;
559 epgTags.firstBlock = firstResultBlock;
560 epgTags.lastBlock = lastResultBlock;
562 for (const auto& tag : tags)
564 if (GetFirstEventBlock(tag) > GetLastEventBlock(tag))
565 continue;
567 epgTags.tags.emplace_back(std::make_shared<CFileItem>(tag));
573 m_firstActiveChannel = firstChannel;
574 m_lastActiveChannel = lastChannel;
575 m_firstActiveBlock = firstBlock;
576 m_lastActiveBlock = lastBlock;
578 return true;
581 void CGUIEPGGridContainerModel::FreeRulerMemory(int keepStart, int keepEnd)
583 if (keepStart < keepEnd)
585 // remove before keepStart and after keepEnd
586 for (int i = 1; i < keepStart && i < RulerItemsSize(); ++i)
587 m_rulerItems[i]->FreeMemory();
588 for (int i = keepEnd + 1; i < RulerItemsSize(); ++i)
589 m_rulerItems[i]->FreeMemory();
591 else
593 // wrapping
594 for (int i = keepEnd + 1; i < keepStart && i < RulerItemsSize(); ++i)
596 if (i == 0)
597 continue;
599 m_rulerItems[i]->FreeMemory();
604 unsigned int CGUIEPGGridContainerModel::GetPageNowOffset() const
606 return GetGridStartPadding() / MINSPERBLOCK; // this is the 'now' block relative to page start
609 CDateTime CGUIEPGGridContainerModel::GetStartTimeForBlock(int block) const
611 if (block < 0)
612 block = 0;
613 else if (block >= GridItemsSize())
614 block = GetLastBlock();
616 return m_gridStart + CDateTimeSpan(0, 0, block * MINSPERBLOCK, 0);
619 int CGUIEPGGridContainerModel::GetBlock(const CDateTime& datetime) const
621 int diff;
623 if (m_gridStart == datetime)
624 return 0; // block is at grid start
625 else if (m_gridStart > datetime)
626 diff = -1 * (m_gridStart - datetime).GetSecondsTotal(); // block is before grid start
627 else
628 diff = (datetime - m_gridStart).GetSecondsTotal(); // block is after grid start
630 // Note: Subtract 1 second from diff to ensure that events ending exactly at block boundary
631 // are unambiguous. Example: An event ending at 5:00:00 shall be mapped to block 9 and
632 // an event starting at 5:00:00 shall be mapped to block 10, not both at block 10.
633 // Only exception is grid end, because there is no successor.
634 if (datetime >= m_gridEnd)
635 return diff / 60 / MINSPERBLOCK; // block is equal or after grid end
636 else
637 return (diff - 1) / 60 / MINSPERBLOCK;
640 int CGUIEPGGridContainerModel::GetNowBlock() const
642 return GetBlock(CDateTime::GetUTCDateTime()) - GetPageNowOffset();
645 int CGUIEPGGridContainerModel::GetFirstEventBlock(
646 const std::shared_ptr<const CPVREpgInfoTag>& event) const
648 const CDateTime eventStart = event->StartAsUTC();
649 int diff;
651 if (m_gridStart == eventStart)
652 return 0; // block is at grid start
653 else if (m_gridStart > eventStart)
654 diff = -1 * (m_gridStart - eventStart).GetSecondsTotal();
655 else
656 diff = (eventStart - m_gridStart).GetSecondsTotal();
658 // First block of a tag is always the block calculated using event's start time, rounded up.
659 float fBlockIndex = diff / 60.0f / MINSPERBLOCK;
660 return static_cast<int>(std::ceil(fBlockIndex));
663 int CGUIEPGGridContainerModel::GetLastEventBlock(
664 const std::shared_ptr<const CPVREpgInfoTag>& event) const
666 // Last block of a tag is always the block calculated using event's end time, not rounded up.
667 return GetBlock(event->EndAsUTC());
670 bool CGUIEPGGridContainerModel::IsEventMemberOfBlock(
671 const std::shared_ptr<const CPVREpgInfoTag>& event, int iBlock) const
673 const int iFirstBlock = GetFirstEventBlock(event);
674 const int iLastBlock = GetLastEventBlock(event);
676 if (iFirstBlock > iLastBlock)
678 return false;
680 else if (iFirstBlock == iBlock)
682 return true;
684 else if (iFirstBlock < iBlock)
686 return (iBlock <= iLastBlock);
688 return false;
691 std::unique_ptr<CFileItemList> CGUIEPGGridContainerModel::GetCurrentTimeLineItems(
692 int firstChannel, int numChannels) const
694 // Note: No need to keep this in a member. Gets generally not called multiple times for the
695 // same timeline, but content must be synced with m_epgItems, which changes quite often.
697 std::unique_ptr<CFileItemList> items(new CFileItemList);
699 if (numChannels > ChannelItemsSize())
700 numChannels = ChannelItemsSize();
702 int i = 0;
703 for (int channel = firstChannel; channel < (firstChannel + numChannels); ++channel)
705 // m_epgItems is not sorted, fileitemlist must be sorted, so we have to 'find' the channel
706 const auto itEpg = m_epgItems.find(channel);
707 if (itEpg != m_epgItems.end())
709 // tags are sorted, so we can iterate and append
710 for (const auto& tag : (*itEpg).second.tags)
712 tag->SetProperty("TimelineIndex", i);
713 items->Add(tag);
714 ++i;
717 else
719 // fake empty EPG
720 const std::shared_ptr<CFileItem> tag = CreateGapItem(channel);
721 tag->SetProperty("TimelineIndex", i);
722 items->Add(tag);
723 ++i;
726 return items;