Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Use background buttonlist loading to speed up the Watch Recordings sc…

…reen.

Fixes #10161.  MythUIButtonList is enhanced with new methods for
loading and fully initializing button list items in the background,
i.e. several items during each iteration of the Qt event loop.  This
can give a faster response time for Watch Recordings, particularly on
weak frontends like ION when there are hundreds or thousands of
recordings.  Previously Recorded is also modified to use background
loading, which is even more dramatic as long-running MythTV
installations may have many thousands of Previously Recorded entries.
  • Loading branch information...
commit 825182e48119190d821c053ac31fb93e8bc2ea19 1 parent 7c7852f
@stichnot stichnot authored
View
51 mythtv/libs/libmythui/mythuibuttonlist.cpp
@@ -86,6 +86,8 @@ void MythUIButtonList::Const(void)
m_buttontemplate = NULL;
+ m_nextItemLoaded = 0;
+
SetCanTakeFocus(true);
connect(this, SIGNAL(TakingFocus()), this, SLOT(Select()));
@@ -153,6 +155,7 @@ void MythUIButtonList::Reset()
m_topPosition = 0;
m_itemCount = 0;
+ StopLoad();
Update();
MythUIType::Reset();
}
@@ -2476,6 +2479,54 @@ bool MythUIButtonList::gestureEvent(MythGestureEvent *event)
return handled;
}
+class NextButtonListPageEvent : public QEvent
+{
+ public:
+ NextButtonListPageEvent(int start, int pageSize) :
+ QEvent(kEventType), m_start(start), m_pageSize(pageSize) {}
+ const int m_start;
+ const int m_pageSize;
+ static Type kEventType;
+};
+
+QEvent::Type NextButtonListPageEvent::kEventType =
+ (QEvent::Type) QEvent::registerEventType();
+
+void MythUIButtonList::customEvent(QEvent *event)
+{
+ if (event->type() == NextButtonListPageEvent::kEventType)
+ {
+ NextButtonListPageEvent *npe =
+ dynamic_cast<NextButtonListPageEvent*>(event);
+ int cur = npe->m_start;
+ for (; cur < npe->m_start + npe->m_pageSize && cur < GetCount(); ++cur)
+ {
+ const int loginterval = (cur < 1000 ? 100 : 500);
+ if (cur % loginterval == 0)
+ LOG(VB_GENERAL, LOG_INFO,
+ QString("Build background buttonlist item %1").arg(cur));
+ emit itemLoaded(GetItemAt(cur));
+ }
+ m_nextItemLoaded = cur;
+ if (cur < GetCount())
+ LoadInBackground(cur, npe->m_pageSize);
+ }
+}
+
+void MythUIButtonList::LoadInBackground(int start, int pageSize)
+{
+ m_nextItemLoaded = start;
+ QCoreApplication::
+ postEvent(this, new NextButtonListPageEvent(start, pageSize));
+}
+
+int MythUIButtonList::StopLoad(void)
+{
+ QCoreApplication::
+ removePostedEvents(this, NextButtonListPageEvent::kEventType);
+ return m_nextItemLoaded;
+}
+
QPoint MythUIButtonList::GetButtonPosition(int column, int row) const
{
int x = m_contentsRect.x() +
View
6 mythtv/libs/libmythui/mythuibuttonlist.h
@@ -128,6 +128,7 @@ class MUI_PUBLIC MythUIButtonList : public MythUIType
virtual bool keyPressEvent(QKeyEvent *);
virtual bool gestureEvent(MythGestureEvent *event);
+ virtual void customEvent(QEvent *);
enum MovementUnit { MoveItem, MoveColumn, MoveRow, MovePage, MoveMax,
MoveMid, MoveByAmount };
@@ -184,6 +185,9 @@ class MUI_PUBLIC MythUIButtonList : public MythUIType
bool FindNext(void);
bool FindPrev(void);
+ void LoadInBackground(int start = 0, int pageSize = 20);
+ int StopLoad(void);
+
public slots:
void Select();
void Deselect();
@@ -192,6 +196,7 @@ class MUI_PUBLIC MythUIButtonList : public MythUIType
void itemSelected(MythUIButtonListItem* item);
void itemClicked(MythUIButtonListItem* item);
void itemVisible(MythUIButtonListItem* item);
+ void itemLoaded(MythUIButtonListItem* item);
protected:
enum ScrollStyle { ScrollFree, ScrollCenter, ScrollGroupCenter };
@@ -302,6 +307,7 @@ class MUI_PUBLIC MythUIButtonList : public MythUIType
bool m_keepSelAtBottom;
QList<MythUIButtonListItem*> m_itemList;
+ int m_nextItemLoaded;
bool m_drawFromBottom;
View
144 mythtv/programs/mythfrontend/playbackbox.cpp
@@ -542,6 +542,8 @@ bool PlaybackBox::Create()
SLOT(PlayFromBookmark(MythUIButtonListItem*)));
connect(m_recordingList, SIGNAL(itemVisible(MythUIButtonListItem*)),
SLOT(ItemVisible(MythUIButtonListItem*)));
+ connect(m_recordingList, SIGNAL(itemLoaded(MythUIButtonListItem*)),
+ SLOT(ItemLoaded(MythUIButtonListItem*)));
// connect up timers...
connect(m_artTimer[kArtworkFanart], SIGNAL(timeout()), SLOT(fanartLoad()));
@@ -890,10 +892,86 @@ void PlaybackBox::UpdateUIListItem(MythUIButtonListItem *item,
}
}
+void PlaybackBox::ItemLoaded(MythUIButtonListItem *item)
+{
+ ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
+ if (item->GetText("is_item_initialized").isNull())
+ {
+ QMap<AudioProps, QString> audioFlags;
+ audioFlags[AUD_DOLBY] = "dolby";
+ audioFlags[AUD_SURROUND] = "surround";
+ audioFlags[AUD_STEREO] = "stereo";
+ audioFlags[AUD_MONO] = "mono";
+
+ QMap<VideoProps, QString> videoFlags;
+ videoFlags[VID_1080] = "hd1080";
+ videoFlags[VID_720] = "hd720";
+ videoFlags[VID_HDTV] = "hdtv";
+ videoFlags[VID_WIDESCREEN] = "widescreen";
+
+ QMap<SubtitleTypes, QString> subtitleFlags;
+ subtitleFlags[SUB_SIGNED] = "deafsigned";
+ subtitleFlags[SUB_ONSCREEN] = "onscreensub";
+ subtitleFlags[SUB_NORMAL] = "subtitles";
+ subtitleFlags[SUB_HARDHEAR] = "cc";
+
+ QString groupname =
+ m_groupList->GetItemCurrent()->GetData().toString();
+
+ QString state = extract_main_state(*pginfo, m_player);
+
+ item->SetFontState(state);
+
+ InfoMap infoMap;
+ pginfo->ToMap(infoMap);
+ item->SetTextFromMap(infoMap);
+
+ QString tempSubTitle = extract_subtitle(*pginfo, groupname);
+
+ if (groupname == pginfo->GetTitle().toLower())
+ item->SetText(tempSubTitle, "titlesubtitle");
+
+ item->DisplayState(state, "status");
+
+ item->DisplayState(QString::number(pginfo->GetStars(10)),
+ "ratingstate");
+
+ SetItemIcons(item, pginfo);
+
+ QMap<AudioProps, QString>::iterator ait;
+ for (ait = audioFlags.begin(); ait != audioFlags.end(); ++ait)
+ {
+ if (pginfo->GetAudioProperties() & ait.key())
+ item->DisplayState(ait.value(), "audioprops");
+ }
+
+ QMap<VideoProps, QString>::iterator vit;
+ for (vit = videoFlags.begin(); vit != videoFlags.end(); ++vit)
+ {
+ if (pginfo->GetVideoProperties() & vit.key())
+ item->DisplayState(vit.value(), "videoprops");
+ }
+
+ QMap<SubtitleTypes, QString>::iterator sit;
+ for (sit = subtitleFlags.begin(); sit != subtitleFlags.end(); ++sit)
+ {
+ if (pginfo->GetSubtitleType() & sit.key())
+ item->DisplayState(sit.value(), "subtitletypes");
+ }
+
+ item->DisplayState(pginfo->GetCategoryType(), "categorytype");
+
+ // Mark this button list item as initialized.
+ item->SetText("yes", "is_item_initialized");
+ }
+
+}
+
void PlaybackBox::ItemVisible(MythUIButtonListItem *item)
{
ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
+ ItemLoaded(item);
// Job status (recording, transcoding, flagging)
QString job = extract_job_state(*pginfo);
item->DisplayState(job, "jobstate");
@@ -1316,24 +1394,6 @@ void PlaybackBox::updateRecList(MythUIButtonListItem *sel_item)
ProgramList &progList = *pmit;
- QMap<AudioProps, QString> audioFlags;
- audioFlags[AUD_DOLBY] = "dolby";
- audioFlags[AUD_SURROUND] = "surround";
- audioFlags[AUD_STEREO] = "stereo";
- audioFlags[AUD_MONO] = "mono";
-
- QMap<VideoProps, QString> videoFlags;
- videoFlags[VID_1080] = "hd1080";
- videoFlags[VID_720] = "hd720";
- videoFlags[VID_HDTV] = "hdtv";
- videoFlags[VID_WIDESCREEN] = "widescreen";
-
- QMap<SubtitleTypes, QString> subtitleFlags;
- subtitleFlags[SUB_SIGNED] = "deafsigned";
- subtitleFlags[SUB_ONSCREEN] = "onscreensub";
- subtitleFlags[SUB_NORMAL] = "subtitles";
- subtitleFlags[SUB_HARDHEAR] = "cc";
-
ProgramList::iterator it = progList.begin();
for (; it != progList.end(); ++it)
{
@@ -1341,51 +1401,9 @@ void PlaybackBox::updateRecList(MythUIButtonListItem *sel_item)
(*it)->GetAvailableStatus() == asDeleted)
continue;
- MythUIButtonListItem *item =
- new PlaybackBoxListItem(this, m_recordingList, *it);
-
- QString state = extract_main_state(**it, m_player);
-
- item->SetFontState(state);
-
- InfoMap infoMap;
- (*it)->ToMap(infoMap);
- item->SetTextFromMap(infoMap);
-
- QString tempSubTitle = extract_subtitle(**it, groupname);
-
- if (groupname == (*it)->GetTitle().toLower())
- item->SetText(tempSubTitle, "titlesubtitle");
-
- item->DisplayState(state, "status");
-
- item->DisplayState(QString::number((*it)->GetStars(10)), "ratingstate");
-
- SetItemIcons(item, (*it));
-
- QMap<AudioProps, QString>::iterator ait;
- for (ait = audioFlags.begin(); ait != audioFlags.end(); ++ait)
- {
- if ((*it)->GetAudioProperties() & ait.key())
- item->DisplayState(ait.value(), "audioprops");
- }
-
- QMap<VideoProps, QString>::iterator vit;
- for (vit = videoFlags.begin(); vit != videoFlags.end(); ++vit)
- {
- if ((*it)->GetVideoProperties() & vit.key())
- item->DisplayState(vit.value(), "videoprops");
- }
-
- QMap<SubtitleTypes, QString>::iterator sit;
- for (sit = subtitleFlags.begin(); sit != subtitleFlags.end(); ++sit)
- {
- if ((*it)->GetSubtitleType() & sit.key())
- item->DisplayState(sit.value(), "subtitletypes");
- }
-
- item->DisplayState((*it)->GetCategoryType(), "categorytype");
+ new PlaybackBoxListItem(this, m_recordingList, *it);
}
+ m_recordingList->LoadInBackground();
if (m_noRecordingsText)
{
@@ -2418,6 +2436,7 @@ bool PlaybackBox::Play(
ProgramInfo tvrec(rec);
m_playingSomething = true;
+ int initIndex = m_recordingList->StopLoad();
uint flags =
(inPlaylist ? kStartTVInPlayList : kStartTVNoFlags) |
@@ -2427,6 +2446,7 @@ bool PlaybackBox::Play(
playCompleted = TV::StartTV(&tvrec, flags);
m_playingSomething = false;
+ m_recordingList->LoadInBackground(initIndex);
if (inPlaylist && !m_playListPlay.empty())
{
View
1  mythtv/programs/mythfrontend/playbackbox.h
@@ -142,6 +142,7 @@ class PlaybackBox : public ScheduleCommon
void ItemSelected(MythUIButtonListItem *item)
{ UpdateUIListItem(item, true); }
void ItemVisible(MythUIButtonListItem *item);
+ void ItemLoaded(MythUIButtonListItem *item);
void selected(MythUIButtonListItem *item);
void PlayFromBookmark(MythUIButtonListItem *item = NULL);
void PlayFromBeginning(MythUIButtonListItem *item = NULL);
View
50 mythtv/programs/mythfrontend/proglist.cpp
@@ -44,6 +44,7 @@ ProgLister::ProgLister(MythScreenStack *parent, ProgListType pltype,
m_viewTextList(),
m_itemList(),
+ m_itemListSave(),
m_schedList(),
m_typeList(),
@@ -93,6 +94,7 @@ ProgLister::ProgLister(
m_viewTextList(),
m_itemList(),
+ m_itemListSave(),
m_schedList(),
m_typeList(),
@@ -115,6 +117,7 @@ ProgLister::ProgLister(
ProgLister::~ProgLister()
{
m_itemList.clear();
+ m_itemListSave.clear();
gCoreContext->removeListener(this);
}
@@ -139,6 +142,12 @@ bool ProgLister::Create()
connect(m_progList, SIGNAL(itemSelected(MythUIButtonListItem*)),
this, SLOT( HandleSelected( MythUIButtonListItem*)));
+ connect(m_progList, SIGNAL(itemVisible(MythUIButtonListItem*)),
+ this, SLOT( HandleVisible( MythUIButtonListItem*)));
+
+ connect(m_progList, SIGNAL(itemLoaded(MythUIButtonListItem*)),
+ this, SLOT( HandleVisible( MythUIButtonListItem*)));
+
connect(m_progList, SIGNAL(itemClicked(MythUIButtonListItem*)),
this, SLOT( HandleClicked()));
@@ -1344,7 +1353,14 @@ void ProgLister::FillItemList(bool restorePosition, bool updateDisp)
selectedP = &selected;
}
+ // Save a copy of m_itemList so that deletion of the ProgramInfo
+ // objects can be deferred until background processing of old
+ // ProgramInfo objects has completed.
+ m_itemListSave.clear();
+ m_itemListSave = m_itemList;
+ m_itemList.setAutoDelete(false);
m_itemList.clear();
+ m_itemList.setAutoDelete(true);
if (m_type == plPreviouslyRecorded)
{
@@ -1491,19 +1507,16 @@ void ProgLister::RestoreSelection(const ProgramInfo *selected,
m_progList->SetItemCurrent(i + 1, i + 1 - selectedOffset);
}
-void ProgLister::UpdateButtonList(void)
+void ProgLister::HandleVisible(MythUIButtonListItem *item)
{
- ProgramList::const_iterator it = m_itemList.begin();
- for (; it != m_itemList.end(); ++it)
- {
- MythUIButtonListItem *item =
- new MythUIButtonListItem(
- m_progList, "", qVariantFromValue(*it));
+ ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
+ if (item->GetText("is_item_initialized").isNull())
+ {
InfoMap infoMap;
- (**it).ToMap(infoMap);
+ pginfo->ToMap(infoMap);
- QString state = toUIState((**it).GetRecordingStatus());
+ QString state = toUIState(pginfo->GetRecordingStatus());
if ((state == "warning") && (plPreviouslyRecorded == m_type))
state = "disabled";
@@ -1511,17 +1524,28 @@ void ProgLister::UpdateButtonList(void)
if (m_type == plTitle)
{
- QString tempSubTitle = (**it).GetSubtitle();
+ QString tempSubTitle = pginfo->GetSubtitle();
if (tempSubTitle.trimmed().isEmpty())
- tempSubTitle = (**it).GetTitle();
+ tempSubTitle = pginfo->GetTitle();
item->SetText(tempSubTitle, "titlesubtitle", state);
}
- item->DisplayState(
- QString::number((**it).GetStars(10)), "ratingstate");
+ item->DisplayState(QString::number(pginfo->GetStars(10)),
+ "ratingstate");
item->DisplayState(state, "status");
+
+ // Mark this button list item as initialized.
+ item->SetText("yes", "is_item_initialized");
}
+}
+
+void ProgLister::UpdateButtonList(void)
+{
+ ProgramList::const_iterator it = m_itemList.begin();
+ for (; it != m_itemList.end(); ++it)
+ new MythUIButtonListItem(m_progList, "", qVariantFromValue(*it));
+ m_progList->LoadInBackground();
if (m_positionText)
{
View
2  mythtv/programs/mythfrontend/proglist.h
@@ -50,6 +50,7 @@ class ProgLister : public ScheduleCommon
protected slots:
void HandleSelected(MythUIButtonListItem *item);
+ void HandleVisible(MythUIButtonListItem *item);
void HandleClicked(void);
void DeleteOldEpisode(bool ok);
@@ -115,6 +116,7 @@ class ProgLister : public ScheduleCommon
QStringList m_viewTextList;
ProgramList m_itemList;
+ ProgramList m_itemListSave;
ProgramList m_schedList;
QStringList m_typeList;
Please sign in to comment.
Something went wrong with that request. Please try again.