Skip to content

Commit

Permalink
Use background buttonlist loading to speed up the Watch Recordings sc…
Browse files Browse the repository at this point in the history
…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
stichnot committed Apr 21, 2012
1 parent 7c7852f commit 825182e
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 75 deletions.
51 changes: 51 additions & 0 deletions mythtv/libs/libmythui/mythuibuttonlist.cpp
Expand Up @@ -86,6 +86,8 @@ void MythUIButtonList::Const(void)

m_buttontemplate = NULL;

m_nextItemLoaded = 0;

SetCanTakeFocus(true);

connect(this, SIGNAL(TakingFocus()), this, SLOT(Select()));
Expand Down Expand Up @@ -153,6 +155,7 @@ void MythUIButtonList::Reset()
m_topPosition = 0;
m_itemCount = 0;

StopLoad();
Update();
MythUIType::Reset();
}
Expand Down Expand Up @@ -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() +
Expand Down
6 changes: 6 additions & 0 deletions mythtv/libs/libmythui/mythuibuttonlist.h
Expand Up @@ -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 };
Expand Down Expand Up @@ -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();
Expand All @@ -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 };
Expand Down Expand Up @@ -302,6 +307,7 @@ class MUI_PUBLIC MythUIButtonList : public MythUIType
bool m_keepSelAtBottom;

QList<MythUIButtonListItem*> m_itemList;
int m_nextItemLoaded;

bool m_drawFromBottom;

Expand Down
144 changes: 82 additions & 62 deletions mythtv/programs/mythfrontend/playbackbox.cpp
Expand Up @@ -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()));
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -1316,76 +1394,16 @@ 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)
{
if ((*it)->GetAvailableStatus() == asPendingDelete ||
(*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)
{
Expand Down Expand Up @@ -2418,6 +2436,7 @@ bool PlaybackBox::Play(
ProgramInfo tvrec(rec);

m_playingSomething = true;
int initIndex = m_recordingList->StopLoad();

uint flags =
(inPlaylist ? kStartTVInPlayList : kStartTVNoFlags) |
Expand All @@ -2427,6 +2446,7 @@ bool PlaybackBox::Play(
playCompleted = TV::StartTV(&tvrec, flags);

m_playingSomething = false;
m_recordingList->LoadInBackground(initIndex);

if (inPlaylist && !m_playListPlay.empty())
{
Expand Down
1 change: 1 addition & 0 deletions mythtv/programs/mythfrontend/playbackbox.h
Expand Up @@ -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);
Expand Down

0 comments on commit 825182e

Please sign in to comment.