Ticket #7603: 7603-pbb-misc-v1.patch

File 7603-pbb-misc-v1.patch, 58.2 KB (added by danielk, 17 years ago)

Misc. PBB fixes, including some related to this ticket

  • programs/mythfrontend/playbackbox.cpp

     
    364364      // Main Recording List support
    365365      m_progsInDB(0),
    366366      // Other state
    367       m_currentItem(NULL),                m_op_on_playlist(false),
     367      m_op_on_playlist(false),
    368368      m_programInfoCache(this),           m_playingSomething(false),
    369369      // Selection state variables
    370370      m_needUpdate(false),
     
    409409        gContext->SaveSetting("DisplayGroupDefaultViewMask", (int)m_viewMask);
    410410    }
    411411
    412     // If user wants to start in watchlist and watchlist is displayed, then
    413     // make it the current group
    414     if (m_watchListStart && (m_viewMask & VIEW_WATCHLIST))
    415         m_currentGroup = m_watchGroupLabel;
    416 
    417412    // This setting is deprecated in favour of viewmask, this just ensures the
    418413    // that it is converted over when upgrading from earlier versions
    419414    if (gContext->GetNumSetting("LiveTVInAllPrograms",0) &&
     
    472467        m_coverartTimer->disconnect(this);
    473468        m_coverartTimer = NULL;
    474469    }
    475 
    476     delete m_currentItem;
    477470}
    478471
    479472bool PlaybackBox::Create()
     
    698691void PlaybackBox::UpdateUIListItem(
    699692    MythUIButtonListItem *item, bool is_sel, bool force_preview_reload)
    700693{
    701     // TODO Make sure playlist DisplayState is respected..
    702 
    703694    if (!item)
    704695        return;
    705696
     
    744735    if (oldimgfile.isEmpty() || force_preview_reload)
    745736        m_helper.GetPreviewImage(*pginfo);
    746737
     738    bool in_playlist = m_playList.contains(pginfo->MakeUniqueKey());
     739    item->DisplayState((in_playlist) ? "yes" : "no", "playlist");
     740
    747741    if ((GetFocusWidget() == m_recordingList) && is_sel)
    748742    {
    749743        InfoMap infoMap;
     
    1001995    }
    1002996}
    1003997
    1004 void PlaybackBox::updateGroupList()
     998void PlaybackBox::UpdateUIGroupList(const QStringList &groupPreferences)
    1005999{
    10061000    m_groupList->Reset();
    10071001
    10081002    if (!m_titleList.isEmpty())
    10091003    {
    1010         MythUIButtonListItem *item = NULL;
    1011 
    1012         QString groupname;
    1013 
    1014         bool foundGroup = false;
     1004        int best_pref = 10000, sel_idx = 0;
    10151005        QStringList::iterator it;
    10161006        for (it = m_titleList.begin(); it != m_titleList.end(); ++it)
    10171007        {
    1018             groupname = (*it).simplified();
     1008            QString groupname = (*it).simplified();
    10191009
     1010            MythUIButtonListItem *item =
     1011                new MythUIButtonListItem(
     1012                    m_groupList, "", qVariantFromValue(groupname.toLower()));
     1013
    10201014            // The first item added to the list will trigger an update of the
    10211015            // associated Recording List, m_needsUpdate should be false unless
    10221016            // this is the currently selected group
    1023             if (groupname.toLower() == m_currentGroup)
     1017            int pref = groupPreferences.indexOf(groupname.toLower());
     1018            if ((pref >= 0) && (pref < best_pref))
    10241019            {
    1025                 m_needUpdate = true;
    1026                 foundGroup = true;
     1020                best_pref = pref;
     1021                sel_idx = m_groupList->GetItemPos(item);
    10271022            }
    10281023
    1029             item = new MythUIButtonListItem(m_groupList, "",
    1030                                         qVariantFromValue(groupname.toLower()));
    1031 
    1032             if (m_needUpdate)
    1033                 m_groupList->SetItemCurrent(item);
    1034 
    10351024            if (groupname.isEmpty())
    10361025                groupname = m_groupDisplayName;
    10371026
     
    10421031            item->SetText(QString::number(count), "reccount");
    10431032        }
    10441033
    1045         if (!foundGroup)
    1046         {
    1047             m_needUpdate = true;
    1048             m_groupList->SetItemCurrent(0);
    1049         }
     1034        m_needUpdate = true;
     1035        m_groupList->SetItemCurrent(sel_idx);
    10501036    }
    10511037}
    10521038
     
    11681154            if ((*it)->subtitleType & sit.key())
    11691155                item->DisplayState(sit.value(), "subtitletypes");
    11701156        }
    1171 
    1172         if (m_currentItem &&
    1173             (m_currentItem->chanid     == (*it)->chanid) &&
    1174             (m_currentItem->recstartts == (*it)->recstartts))
    1175         {
    1176             m_recordingList->SetItemCurrent(item);
    1177         }
    11781157    }
    11791158
    11801159    if (m_noRecordingsText)
     
    11941173
    11951174bool PlaybackBox::UpdateUILists(void)
    11961175{
    1197     // TODO Make sure playlist DisplayState is respected..
    1198 
    11991176    m_isFilling = true;
    12001177
    1201     if (m_currentItem)
     1178    // Save selection, including next few items & groups
     1179    QStringList groupSelPref;
     1180    QStringList itemSelPref;
     1181    MythUIButtonListItem *prefSelGroup = m_groupList->GetItemCurrent();
     1182    if (prefSelGroup)
    12021183    {
    1203         delete m_currentItem;
    1204         m_currentItem = NULL;
     1184        groupSelPref.push_back(prefSelGroup->GetData().toString());
     1185        for (int i = m_groupList->GetCurrentPos();
     1186             i < m_groupList->GetCount(); i++)
     1187        {
     1188            prefSelGroup = m_groupList->GetItemAt(i);
     1189            if (prefSelGroup)
     1190                groupSelPref.push_back(prefSelGroup->GetData().toString());
     1191        }
     1192
     1193        int curPos = m_recordingList->GetCurrentPos();
     1194        for (int i = curPos; i < m_recordingList->GetCount(); i++)
     1195        {
     1196            MythUIButtonListItem *item = m_recordingList->GetItemAt(i);
     1197            ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
     1198            itemSelPref.push_back(groupSelPref.front());
     1199            itemSelPref.push_back(pginfo->MakeUniqueKey());
     1200        }
     1201        if (curPos >= m_recordingList->GetCount())
     1202            curPos = -1;
     1203        for (int i = curPos; i >= 0; i--)
     1204        {
     1205            MythUIButtonListItem *item = m_recordingList->GetItemAt(i);
     1206            ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
     1207            itemSelPref.push_back(groupSelPref.front());
     1208            itemSelPref.push_back(pginfo->MakeUniqueKey());
     1209        }
    12051210    }
     1211    else
     1212    {
     1213        // If user wants to start in watchlist and watchlist is displayed, then
     1214        // make it the current group
     1215        if (m_watchListStart && (m_viewMask & VIEW_WATCHLIST))
     1216            groupSelPref.push_back(m_watchGroupLabel);
     1217    }
    12061218
    1207     ProgramInfo *tmp = CurrentItem();
    1208     if (tmp)
    1209         m_currentItem = new ProgramInfo(*tmp);
    1210 
     1219    // Cache available status for later restoration
    12111220    QMap<QString, AvailableStatusType> asCache;
    12121221    QString asKey;
    12131222
     
    16701679        }
    16711680    }
    16721681
    1673     updateGroupList();
     1682    UpdateUIGroupList(groupSelPref);
    16741683    UpdateUsageUI();
    16751684
    1676     if (m_currentItem)
     1685    QStringList::const_iterator it = m_playList.begin();
     1686    for (; it != m_playList.end(); ++it)
    16771687    {
    1678         delete m_currentItem;
    1679         m_currentItem = NULL;
     1688        ProgramInfo *pginfo = FindProgramInUILists(*it);
     1689        if (!pginfo)
     1690            continue;
     1691        MythUIButtonListItem *item =
     1692            m_recordingList->GetItemByData(qVariantFromValue(pginfo));
     1693        if (item)
     1694            item->DisplayState("yes", "playlist");
    16801695    }
    16811696
     1697    // If possible reselect the item selected before,
     1698    // otherwise select the nearest available item.
     1699    prefSelGroup = m_groupList->GetItemCurrent();
     1700    if (prefSelGroup &&
     1701        groupSelPref.contains(prefSelGroup->GetData().toString()) &&
     1702        itemSelPref.contains(prefSelGroup->GetData().toString()))
     1703    {
     1704        // the group is selected above in UpdateUIGroupList()
     1705        QString groupname = prefSelGroup->GetData().toString();
     1706        VERBOSE(VB_IMPORTANT, QString("Selected Group: '%1'")
     1707                .arg(groupname));
     1708        for (uint i = 0; i+1 < (uint)itemSelPref.size(); i+=2)
     1709        {
     1710            VERBOSE(VB_IMPORTANT, QString("Checking '%1':%2")
     1711                    .arg(itemSelPref[i]).arg(itemSelPref[i+1]));
     1712
     1713            if (itemSelPref[i] != groupname)
     1714                continue;
     1715
     1716            const QString key = itemSelPref[i+1];
     1717            for (uint j = 0; j < (uint)m_recordingList->GetCount(); j++)
     1718            {
     1719                MythUIButtonListItem *item = m_recordingList->GetItemAt(j);
     1720                ProgramInfo *pginfo =
     1721                    qVariantValue<ProgramInfo*>(item->GetData());
     1722                if (i==0 && pginfo)
     1723                {
     1724                    VERBOSE(VB_IMPORTANT, QString(" against %1")
     1725                            .arg(pginfo->MakeUniqueKey()));
     1726                }
     1727                if (pginfo && (pginfo->MakeUniqueKey() == key))
     1728                {
     1729                    VERBOSE(VB_IMPORTANT, "Reselect success");
     1730                    m_recordingList->SetItemCurrent(j);
     1731                    i = itemSelPref.size();
     1732                    break;
     1733                }
     1734            }
     1735        }
     1736    }
     1737    else
     1738    {
     1739        VERBOSE(VB_IMPORTANT, QString("prefSelGroup: 0x%1 in list of %2")
     1740                .arg((uint64_t)prefSelGroup).arg(m_groupList->GetCount()));
     1741    }
     1742
     1743    VERBOSE(VB_IMPORTANT, "UpdateUILists() -- end");
     1744
    16821745    m_isFilling = false;
    16831746
    16841747    return true;
     
    16861749
    16871750void PlaybackBox::playSelectedPlaylist(bool random)
    16881751{
    1689     ProgramInfo *tmpItem;
    1690     QStringList::Iterator it = m_playList.begin();
    1691     QStringList randomList = m_playList;
    1692     bool playNext = true;
    1693     int i = 0;
    1694 
    1695     while (randomList.size() && playNext)
     1752    if (random)
    16961753    {
    1697         if (random)
    1698             i = (int)(1.0 * randomList.size() * rand() / (RAND_MAX + 1.0));
     1754        m_playListPlay.clear();
     1755        QStringList tmp = m_playList;
     1756        while (!tmp.empty())
     1757        {
     1758            uint i = rand() % tmp.size();
     1759            m_playListPlay.push_back(tmp[i]);
     1760            tmp.removeAll(tmp[i]);
     1761        }
     1762    }
     1763    else
     1764    {
     1765        m_playListPlay = m_playList;
     1766    }
    16991767
    1700         it = randomList.begin() + i;
    1701 
    1702         tmpItem = FindProgramInUILists(*it);
    1703 
    1704         if ((tmpItem->availableStatus == asAvailable) ||
    1705             (tmpItem->availableStatus == asNotYetAvailable))
    1706             playNext = play(tmpItem, true);
    1707 
    1708         randomList.erase(it);
    1709     }
     1768    QCoreApplication::postEvent(
     1769        this, new MythEvent("PLAY_PLAYLIST"));
    17101770}
    17111771
    17121772void PlaybackBox::playSelected(MythUIButtonListItem *item)
     
    17281788        return;
    17291789    }
    17301790
    1731     if ((pginfo->availableStatus == asAvailable) ||
    1732         (pginfo->availableStatus == asNotYetAvailable))
    1733         play(pginfo);
    1734     else
    1735         showAvailablePopup(pginfo);
    1736 
     1791    Play(*pginfo, false);
    17371792}
    17381793
    17391794void PlaybackBox::StopSelected(void)
     
    17671822        push_onto_del(m_delList, *pginfo);
    17681823        ShowDeletePopup(kDeleteRecording);
    17691824    }
    1770     else
    1771         showAvailablePopup(pginfo);
    17721825}
    17731826
    17741827void PlaybackBox::upcoming()
    17751828{
    1776    ProgramInfo *pginfo = CurrentItem();
    1777 
    1778     if (!pginfo)
    1779         return;
    1780 
    1781     if (pginfo->availableStatus != asAvailable)
    1782     {
    1783         showAvailablePopup(pginfo);
    1784         return;
    1785     }
    1786 
    1787     ShowUpcoming(pginfo);
     1829    ProgramInfo *pginfo = CurrentItem();
     1830    if (pginfo)
     1831        ShowUpcoming(pginfo);
    17881832}
    17891833
    17901834ProgramInfo *PlaybackBox::CurrentItem(void)
     
    18071851void PlaybackBox::customEdit()
    18081852{
    18091853    ProgramInfo *pginfo = CurrentItem();
    1810 
    1811     if (!pginfo)
    1812         return;
    1813 
    1814     if (pginfo->availableStatus != asAvailable)
    1815     {
    1816         showAvailablePopup(pginfo);
    1817         return;
    1818     }
    1819 
    1820     EditCustom(pginfo);
     1854    if (pginfo)
     1855        EditCustom(pginfo);
    18211856}
    18221857
    18231858void PlaybackBox::details()
    18241859{
    18251860    ProgramInfo *pginfo = CurrentItem();
    1826 
    1827     if (!pginfo)
    1828         return;
    1829 
    1830     if (pginfo->availableStatus != asAvailable)
    1831         showAvailablePopup(pginfo);
    1832     else
     1861    if (pginfo)
    18331862        ShowDetails(pginfo);
    18341863}
    18351864
     
    18951924            m_popupMenu->AddButton(tr("Add this Group to Playlist"),
    18961925                             SLOT(togglePlayListTitle()));
    18971926        }
    1898         else if (pginfo && pginfo->availableStatus == asAvailable)
     1927        else if (pginfo)
    18991928        {
    19001929            m_popupMenu->AddButton(tr("Add this recording to Playlist"),
    19011930                                        SLOT(togglePlayListItem()));
     
    19051934    m_popupMenu->AddButton(tr("Help (Status Icons)"), SLOT(showIconHelp()));
    19061935}
    19071936
    1908 void PlaybackBox::showActionsSelected()
     1937bool PlaybackBox::Play(const ProgramInfo &rec, bool inPlaylist)
    19091938{
    1910     if (GetFocusWidget() == m_groupList)
    1911         return;
    1912 
    1913     ProgramInfo *pginfo = CurrentItem();
    1914 
    1915     if (!pginfo)
    1916         return;
    1917 
    1918     if ((pginfo->availableStatus != asAvailable) &&
    1919         (pginfo->availableStatus != asFileNotFound))
    1920         showAvailablePopup(pginfo);
    1921     else
    1922         showActions(pginfo);
    1923 }
    1924 
    1925 bool PlaybackBox::play(ProgramInfo *rec, bool inPlaylist)
    1926 {
    19271939    bool playCompleted = false;
    19281940
    1929     if (!rec)
    1930         return false;
    1931 
    19321941    if (m_player)
    19331942        return true;
    19341943
    1935     // TODO do this in another thread
    1936     rec->pathname = rec->GetPlaybackURL(true);
    1937 
    1938     if (rec->availableStatus == asNotYetAvailable)
    1939         rec->availableStatus = asAvailable;
    1940 
    1941     // TODO do this in another thread
    1942     if (!rec->IsFileReadable())
     1944    if ((asAvailable != rec.availableStatus) || (0 == rec.filesize) ||
     1945        (rec.GetRecordBasename() == rec.pathname))
    19431946    {
    1944         VERBOSE(VB_IMPORTANT, QString("PlaybackBox::play(): Error, %1 file "
    1945                                       "not found").arg(rec->pathname));
    1946 
    1947         if (rec->recstatus == rsRecording)
    1948             rec->availableStatus = asNotYetAvailable;
    1949         else
    1950             rec->availableStatus = asFileNotFound;
    1951 
    1952         showAvailablePopup(rec);
    1953 
     1947        m_helper.CheckAvailability(
     1948            rec, (inPlaylist) ? kCheckForPlaylistAction : kCheckForPlayAction);
    19541949        return false;
    19551950    }
    19561951
    1957     if ((rec->filesize == 0) && (rec->GetFilesize() == 0))
    1958     {
    1959         VERBOSE(VB_IMPORTANT,
    1960             QString("PlaybackBox::play(): Error, %1 is zero-bytes in size")
    1961             .arg(rec->pathname));
     1952    ProgramInfo *tvrec = new ProgramInfo(rec);
    19621953
    1963         if (rec->recstatus == rsRecording)
    1964             rec->availableStatus = asNotYetAvailable;
    1965         else
    1966             rec->availableStatus = asZeroByte;
    1967 
    1968         showAvailablePopup(rec);
    1969 
    1970         return false;
    1971     }
    1972 
    1973     ProgramInfo *tvrec = new ProgramInfo(*rec);
    1974 
    19751954    m_playingSomething = true;
    19761955
    1977     playCompleted = TV::StartTV(tvrec, false, inPlaylist, m_underNetworkControl);
     1956    playCompleted = TV::StartTV(
     1957        tvrec, false, inPlaylist, m_underNetworkControl);
    19781958
    19791959    m_playingSomething = false;
    19801960
    19811961    delete tvrec;
    19821962
    1983     UpdateUILists();
     1963    if (inPlaylist && !m_playListPlay.empty())
     1964    {
     1965        QCoreApplication::postEvent(
     1966            this, new MythEvent("PLAY_PLAYLIST"));
     1967    }
    19841968
    19851969    return playCompleted;
    19861970}
     
    20061990        ((delItem->availableStatus == asPendingDelete) ||
    20071991        (!REC_CAN_BE_DELETED(delItem))))
    20081992    {
    2009         showAvailablePopup(delItem);
    20101993        return;
    20111994    }
    20121995
     
    20161999    if (!forceMetadataDelete)
    20172000        delItem->UpdateLastDelete(true);
    20182001
     2002    delItem->availableStatus = asPendingDelete;
    20192003    m_helper.DeleteRecording(
    20202004        delItem->chanid.toUInt(), delItem->recstartts, forceMetadataDelete);
    20212005
     
    22142198        return QString();
    22152199}
    22162200
    2217 void PlaybackBox::showActions(ProgramInfo *pginfo)
    2218 {
    2219     if (!pginfo)
    2220         return;
    2221 
    2222     // TODO do this in another thread (IsFileReadable remote check)
    2223     if (!pginfo->IsFileReadable())
    2224     {
    2225         VERBOSE(VB_IMPORTANT, QString("PlaybackBox::showActions(): Error, %1 "
    2226                                       "file not found").arg(pginfo->pathname));
    2227 
    2228         pginfo->availableStatus = asFileNotFound;
    2229         showFileNotFoundActionPopup(pginfo);
    2230     }
    2231     else if (pginfo->availableStatus != asAvailable)
    2232         showAvailablePopup(pginfo);
    2233     else
    2234         showActionPopup(pginfo);
    2235 }
    2236 
    22372201void PlaybackBox::doPIPPlay(void)
    22382202{
    22392203    doPIPPlay(kPIPonTV);
     
    22912255
    22922256    uint other_delete_cnt = (m_delList.size() / 3) - 1;
    22932257
    2294     popupString(delItem, label);
     2258    label += CreateProgramInfoString(*delItem);
    22952259
    22962260    m_popupMenu = new MythDialogBox(label, m_popupStack, "pbbmainmenupopup");
    22972261
     
    23712335    }
    23722336}
    23732337
    2374 void PlaybackBox::showAvailablePopup(ProgramInfo *rec)
     2338void PlaybackBox::ShowAvailabilityPopup(const ProgramInfo &pginfo)
    23752339{
    2376     if (!rec)
    2377         return;
    2378 
    2379     QString msg = rec->title;
    2380     if (!rec->subtitle.isEmpty())
    2381         msg += " \"" + rec->subtitle + "\"";
     2340    QString msg = pginfo.title;
     2341    if (!pginfo.subtitle.isEmpty())
     2342        msg += " \"" + pginfo.subtitle + "\"";
    23822343    msg += "\n";
    23832344
    2384     switch (rec->availableStatus)
     2345    switch (pginfo.availableStatus)
    23852346    {
    23862347        case asAvailable:
    2387                  if (rec->programflags & (FL_INUSERECORDING | FL_INUSEPLAYING))
    2388                  {
    2389                      QString byWho;
    2390                      rec->IsInUse(byWho);
     2348            if (pginfo.programflags & (FL_INUSERECORDING | FL_INUSEPLAYING))
     2349            {
     2350                QString byWho;
     2351                pginfo.IsInUse(byWho);
    23912352
    2392                      ShowOkPopup(tr("Recording Available\n") + msg +
    2393                                  tr("This recording is currently in "
    2394                                                "use by:") + "\n" + byWho);
    2395                  }
    2396                  else
    2397                  {
    2398                      ShowOkPopup(tr("Recording Available\n") + msg +
    2399                                  tr("This recording is currently "
    2400                                                "Available"));
    2401                  }
    2402                  break;
     2353                ShowOkPopup(tr("Recording Available\n") + msg +
     2354                            tr("This recording is currently in "
     2355                               "use by:") + "\n" + byWho);
     2356            }
     2357            else
     2358            {
     2359                ShowOkPopup(tr("Recording Available\n") + msg +
     2360                            tr("This recording is currently "
     2361                               "Available"));
     2362            }
     2363            break;
    24032364        case asPendingDelete:
    2404                  ShowOkPopup(tr("Recording Unavailable\n") + msg +
    2405                              tr("This recording is currently being "
    2406                                            "deleted and is unavailable"));
    2407                  break;
     2365            ShowOkPopup(tr("Recording Unavailable\n") + msg +
     2366                        tr("This recording is currently being "
     2367                           "deleted and is unavailable"));
     2368            break;
    24082369        case asFileNotFound:
    2409                  ShowOkPopup(tr("Recording Unavailable\n") + msg +
    2410                              tr("The file for this recording can "
    2411                                            "not be found"));
    2412                  break;
     2370            ShowOkPopup(tr("Recording Unavailable\n") + msg +
     2371                        tr("The file for this recording can "
     2372                           "not be found"));
     2373            break;
    24132374        case asZeroByte:
    2414                  ShowOkPopup(tr("Recording Unavailable\n") + msg +
    2415                              tr("The file for this recording is "
    2416                                            "empty."));
    2417                  break;
     2375            ShowOkPopup(tr("Recording Unavailable\n") + msg +
     2376                        tr("The file for this recording is "
     2377                           "empty."));
     2378            break;
    24182379        case asNotYetAvailable:
    2419                  ShowOkPopup(tr("Recording Unavailable\n") + msg +
    2420                              tr("This recording is not yet "
    2421                                            "available."));
     2380            ShowOkPopup(tr("Recording Unavailable\n") + msg +
     2381                        tr("This recording is not yet "
     2382                           "available."));
    24222383    }
    24232384}
    24242385
    24252386void PlaybackBox::showPlaylistPopup()
    24262387{
    2427     if (m_popupMenu)
     2388    if (!CreatePopupMenuPlaylist())
    24282389        return;
    24292390
    2430     if (!(m_popupMenu = createPlaylistPopupMenu()))
    2431         return;
    2432 
    24332391    m_popupMenu->AddButton(tr("Play"), SLOT(doPlayList()));
    24342392    m_popupMenu->AddButton(tr("Shuffle Play"), SLOT(doPlayListRandom()));
    24352393    m_popupMenu->AddButton(tr("Clear Playlist"), SLOT(doClearPlaylist()));
     
    24582416
    24592417void PlaybackBox::showPlaylistStoragePopup()
    24602418{
    2461     if (m_popupMenu)
     2419    if (!CreatePopupMenuPlaylist())
    24622420        return;
    24632421
    2464     if (!(m_popupMenu = createPlaylistPopupMenu()))
    2465         return;
    2466 
    24672422    m_popupMenu->AddButton(tr("Change Recording Group"),
    24682423                           SLOT(ShowRecGroupChangerUsePlaylist()));
    24692424    m_popupMenu->AddButton(tr("Change Playback Group"),
     
    24742429                           SLOT(doPlaylistExpireSetOn()));
    24752430}
    24762431
    2477 void PlaybackBox::showPlaylistJobPopup()
     2432void PlaybackBox::showPlaylistJobPopup(void)
    24782433{
    2479     if (m_popupMenu)
     2434    if (!CreatePopupMenuPlaylist())
    24802435        return;
    24812436
    2482     if (!(m_popupMenu = createPlaylistPopupMenu()))
    2483         return;
    2484 
    24852437    QString jobTitle;
    24862438    QString command;
    24872439    QStringList::Iterator it;
     
    25892541    }
    25902542}
    25912543
    2592 MythDialogBox *PlaybackBox::createPopupMenu(const QString &label)
     2544bool PlaybackBox::CreatePopupMenu(const QString &label)
    25932545{
    25942546    if (m_popupMenu)
    2595         return NULL;
     2547        return false;
    25962548
    25972549    m_popupMenu = new MythDialogBox(label, m_popupStack, "pbbmainmenupopup");
    25982550
    25992551    if (!m_popupMenu)
    2600         return NULL;
     2552        return false;
    26012553
    26022554    connect(m_popupMenu, SIGNAL(Exiting()), SLOT(popupClosed()));
    26032555
     
    26102562    {
    26112563        delete m_popupMenu;
    26122564        m_popupMenu = NULL;
    2613         return NULL;
     2565        return false;
    26142566    }
    26152567
    26162568    return m_popupMenu;
    26172569}
    26182570
    2619 MythDialogBox *PlaybackBox::createProgramPopupMenu(const QString &title,
    2620                                                    ProgramInfo *pginfo)
     2571bool PlaybackBox::CreatePopupMenuPlaylist(void)
    26212572{
    2622     if (m_popupMenu)
    2623         return NULL;
    2624 
    2625     QString label = title;
    2626     if (pginfo)
    2627     {
    2628         popupString(pginfo, label);
    2629     }
    2630     else
    2631     {
    2632         ProgramInfo *pginfo = CurrentItem();
    2633         popupString(pginfo, label);
    2634     }
    2635 
    2636     return createPopupMenu(label);
     2573    return CreatePopupMenu(
     2574        tr("There is %n item(s) in the playlist. Actions affect "
     2575           "all items in the playlist", "", m_playList.size()));
    26372576}
    26382577
    2639 MythDialogBox *PlaybackBox::createPlaylistPopupMenu()
    2640 {
    2641     if (m_popupMenu)
    2642         return NULL;
    2643 
    2644     QString label = tr("There is %n item(s) in the playlist. Actions affect "
    2645                        "all items in the playlist", "", m_playList.size());
    2646 
    2647     return createPopupMenu(label);
    2648 }
    2649 
    26502578void PlaybackBox::showPlayFromPopup()
    26512579{
    2652     if (m_popupMenu)
     2580    ProgramInfo *pginfo = CurrentItem();
     2581    if (!pginfo || !CreatePopupMenu(tr("Play Options"), *pginfo))
    26532582        return;
    26542583
    2655     if (!(m_popupMenu = createProgramPopupMenu(tr("Play Options"))))
    2656         return;
    2657 
    26582584    m_popupMenu->AddButton(tr("Play from bookmark"), SLOT(playSelected()));
    26592585    m_popupMenu->AddButton(tr("Play from beginning"), SLOT(doPlayFromBeg()));
    26602586}
    26612587
    26622588void PlaybackBox::showStoragePopup()
    26632589{
    2664     if (m_popupMenu)
     2590    ProgramInfo *pginfo = CurrentItem();
     2591    if (!pginfo || !CreatePopupMenu(tr("Storage Options"), *pginfo))
    26652592        return;
    26662593
    2667     if (!(m_popupMenu = createProgramPopupMenu(tr("Storage Options"))))
    2668         return;
    2669 
    26702594    m_popupMenu->AddButton(tr("Change Recording Group"),
    26712595                           SLOT(ShowRecGroupChanger()));
    26722596
    26732597    m_popupMenu->AddButton(tr("Change Playback Group"),
    26742598                           SLOT(ShowPlayGroupChanger()));
    26752599
    2676     ProgramInfo *pginfo = CurrentItem();
    26772600    if (pginfo)
    26782601    {
    26792602        if (pginfo->programflags & FL_AUTOEXP)
     
    26942617
    26952618void PlaybackBox::showRecordingPopup()
    26962619{
    2697     if (m_popupMenu)
     2620    ProgramInfo *pginfo = CurrentItem();
     2621    if (!pginfo || !CreatePopupMenu(tr("Scheduling Options"), *pginfo))
    26982622        return;
    26992623
    2700     if (!(m_popupMenu = createProgramPopupMenu(tr("Scheduling Options"))))
    2701         return;
    2702 
    27032624    m_popupMenu->AddButton(tr("Edit Recording Schedule"),
    27042625                            SLOT(doEditScheduled()));
    27052626
     
    27152636
    27162637void PlaybackBox::showJobPopup()
    27172638{
    2718     if (m_popupMenu)
    2719         return;
    2720 
    2721     if (!(m_popupMenu = createProgramPopupMenu(tr("Job Options"))))
    2722         return;
    2723 
    27242639    ProgramInfo *pginfo = CurrentItem();
    2725     if (!pginfo)
     2640    if (!pginfo || !CreatePopupMenu(tr("Job Options"), *pginfo))
    27262641        return;
    27272642
    27282643    QString jobTitle;
     
    28032718
    28042719void PlaybackBox::showTranscodingProfiles()
    28052720{
    2806     if (m_popupMenu)
     2721    if (!CreatePopupMenu(tr("Transcoding profiles")))
    28072722        return;
    28082723
    2809     if (!(m_popupMenu = createPopupMenu(tr("Transcoding profiles"))))
    2810         return;
    2811 
    28122724    m_popupMenu->AddButton(tr("Default"), SLOT(doBeginTranscoding()));
    28132725    m_popupMenu->AddButton(tr("Autodetect"),
    28142726                                    SLOT(changeProfileAndTranscodeAuto()));
     
    28322744    doBeginTranscoding();
    28332745}
    28342746
    2835 void PlaybackBox::showActionPopup(ProgramInfo *pginfo)
     2747void PlaybackBox::ShowActionPopup(const ProgramInfo &pginfo)
    28362748{
    2837     if (m_popupMenu || !pginfo)
     2749    QString label =
     2750        (asFileNotFound == pginfo.availableStatus) ?
     2751        tr("Recording file can not be found") :
     2752        (asZeroByte     == pginfo.availableStatus) ?
     2753        tr("Recording file contains no data") :
     2754        tr("Recording Options");
     2755
     2756    if (!CreatePopupMenu(label, pginfo))
    28382757        return;
    28392758
    2840     QString label = tr("Recording Options");
    2841     if (!(m_popupMenu = createProgramPopupMenu(label, pginfo)))
     2759    if ((asFileNotFound  == pginfo.availableStatus) ||
     2760        (asZeroByte      == pginfo.availableStatus))
     2761    {
     2762        m_popupMenu->AddButton(
     2763            tr("Show Program Details"), SLOT(showProgramDetails()));
     2764        m_popupMenu->AddButton(
     2765            tr("Delete"),               SLOT(askDelete()));
     2766
     2767        if (m_playList.filter(pginfo.MakeUniqueKey()).size())
     2768        {
     2769            m_popupMenu->AddButton(
     2770                tr("Remove from Playlist"), SLOT(togglePlayListItem()));
     2771        }
     2772        else
     2773        {
     2774            m_popupMenu->AddButton(
     2775                tr("Add to Playlist"),      SLOT(togglePlayListItem()));
     2776        }
     2777
    28422778        return;
     2779    }
    28432780
    28442781    bool sameProgram = false;
    28452782
    28462783    if (m_player)
    2847         sameProgram = m_player->IsSameProgram(0, pginfo);
     2784        sameProgram = m_player->IsSameProgram(0, &pginfo);
    28482785
    28492786    TVState tvstate = kState_None;
    28502787    if (m_player)
     
    28582795    }
    28592796    else
    28602797    {
    2861         if (pginfo->programflags & FL_BOOKMARK)
     2798        if (pginfo.programflags & FL_BOOKMARK)
    28622799            m_popupMenu->AddButton(tr("Play from..."),
    28632800                                        SLOT(showPlayFromPopup()), true);
    28642801        else
    28652802            m_popupMenu->AddButton(tr("Play"), SLOT(playSelected()));
    28662803
    2867         if (m_playList.filter(pginfo->MakeUniqueKey()).size())
     2804        if (m_playList.filter(pginfo.MakeUniqueKey()).size())
    28682805            m_popupMenu->AddButton(tr("Remove from Playlist"),
    28692806                                        SLOT(togglePlayListItem()));
    28702807        else
     
    28722809                                        SLOT(togglePlayListItem()));
    28732810    }
    28742811
    2875     if (pginfo->recstatus == rsRecording &&
     2812    if (pginfo.recstatus == rsRecording &&
    28762813        (!(sameProgram &&
    28772814            (tvstate == kState_WatchingLiveTV ||
    28782815                tvstate == kState_WatchingRecording))))
     
    28802817        m_popupMenu->AddButton(tr("Stop Recording"), SLOT(askStop()));
    28812818    }
    28822819
    2883     if (pginfo->programflags & FL_WATCHED)
     2820    if (pginfo.programflags & FL_WATCHED)
    28842821        m_popupMenu->AddButton(tr("Mark as Unwatched"), SLOT(toggleWatched()));
    28852822    else
    28862823        m_popupMenu->AddButton(tr("Mark as Watched"), SLOT(toggleWatched()));
     
    28932830
    28942831    if (!sameProgram)
    28952832    {
    2896         if (pginfo->recgroup == "Deleted")
     2833        if (pginfo.recgroup == "Deleted")
    28972834        {
    2898             push_onto_del(m_delList, *pginfo);
     2835            push_onto_del(m_delList, pginfo);
    28992836            m_popupMenu->AddButton(
    29002837                tr("Undelete"),       SLOT(Undelete()));
    29012838            m_popupMenu->AddButton(
     
    29082845    }
    29092846}
    29102847
    2911 void PlaybackBox::showFileNotFoundActionPopup(ProgramInfo *pginfo)
     2848QString PlaybackBox::CreateProgramInfoString(const ProgramInfo &pginfo) const
    29122849{
    2913     if (m_popupMenu || !pginfo)
    2914         return;
     2850    QDateTime recstartts = pginfo.recstartts;
     2851    QDateTime recendts = pginfo.recendts;
    29152852
    2916     QString label = tr("Recording file can not be found");
    2917     if (!(m_popupMenu = createProgramPopupMenu(label, pginfo)))
    2918         return;
    2919 
    2920     m_popupMenu->AddButton(tr("Show Program Details"),
    2921                                 SLOT(showProgramDetails()));
    2922     m_popupMenu->AddButton(tr("Delete"), SLOT(askDelete()));
    2923 }
    2924 
    2925 void PlaybackBox::popupString(ProgramInfo *program, QString &message)
    2926 {
    2927     if (!program)
    2928         return;
    2929 
    2930     QDateTime recstartts = program->recstartts;
    2931     QDateTime recendts = program->recendts;
    2932 
    29332853    QString timedate = QString("%1, %2 - %3")
    2934                         .arg(recstartts.date().toString(m_formatLongDate))
    2935                         .arg(recstartts.time().toString(m_formatTime))
    2936                         .arg(recendts.time().toString(m_formatTime));
     2854        .arg(recstartts.date().toString(m_formatLongDate))
     2855        .arg(recstartts.time().toString(m_formatTime))
     2856        .arg(recendts.time().toString(m_formatTime));
    29372857
    2938     QString title = program->title;
     2858    QString title = pginfo.title;
    29392859
    29402860    QString extra;
    29412861
    2942     if (!program->subtitle.isEmpty())
     2862    if (!pginfo.subtitle.isEmpty())
    29432863    {
    2944         extra = program->subtitle;
    2945         extra = (title.length() + extra.length() + 2 <= message.length()) ?
    2946             QString(" -- ") + extra : QString('\n') + extra;
    2947 
    2948         int maxll = max(max(message.length(),title.length()), 20);
     2864        extra = QString('\n') + pginfo.subtitle;
     2865        int maxll = max(title.length(), 20);
    29492866        if (extra.length() > maxll)
    29502867            extra = extra.left(maxll - 3) + "...";
    29512868    }
    29522869
    2953     message = QString("%1\n%2%3\n%4")
    2954         .arg(message).arg(title).arg(extra).arg(timedate);
     2870    return QString("\n%1%2\n%3").arg(title).arg(extra).arg(timedate);
    29552871}
    29562872
    29572873void PlaybackBox::doClearPlaylist(void)
     
    29652881            continue;
    29662882
    29672883        MythUIButtonListItem *item =
    2968                         m_recordingList->GetItemByData(qVariantFromValue(tmpItem));
     2884            m_recordingList->GetItemByData(qVariantFromValue(tmpItem));
    29692885
    29702886        if (item)
    29712887            item->DisplayState("no", "playlist");
     
    29762892void PlaybackBox::doPlayFromBeg(void)
    29772893{
    29782894    ProgramInfo *pginfo = CurrentItem();
    2979     pginfo->setIgnoreBookmark(true);
    2980     playSelected(m_recordingList->GetItemCurrent());
     2895    if (pginfo)
     2896    {
     2897        pginfo->setIgnoreBookmark(true);
     2898        playSelected(m_recordingList->GetItemCurrent());
     2899    }
    29812900}
    29822901
    29832902void PlaybackBox::doPlayList(void)
     
    30032922
    30042923void PlaybackBox::showProgramDetails()
    30052924{
    3006    ProgramInfo *pginfo = CurrentItem();
    3007 
     2925    ProgramInfo *pginfo = CurrentItem();
    30082926    if (pginfo)
    30092927        ShowDetails(pginfo);
    30102928}
    30112929
    30122930void PlaybackBox::doEditScheduled()
    30132931{
    3014    ProgramInfo *pginfo = CurrentItem();
    3015 
    3016     if (!pginfo)
    3017         return;
    3018 
    3019     if (pginfo->availableStatus != asAvailable)
    3020         showAvailablePopup(pginfo);
    3021     else
     2932    ProgramInfo *pginfo = CurrentItem();
     2933    if (pginfo)
    30222934        EditScheduled(pginfo);
    30232935}
    30242936
     
    31443056    QStringList list;
    31453057    for (it = m_playList.begin(); it != m_playList.end(); ++it)
    31463058    {
    3147         const ProgramInfo *tmpItem = FindProgramInUILists(*it);
     3059        ProgramInfo *tmpItem = FindProgramInUILists(*it);
    31483060        if (tmpItem && (REC_CAN_BE_DELETED(tmpItem)))
    31493061        {
     3062            tmpItem->availableStatus = asPendingDelete;
    31503063            list.push_back(tmpItem->chanid);
    31513064            list.push_back(tmpItem->recstartts.toString(Qt::ISODate));
    31523065            list.push_back(forceDeleteStr);
     
    31593072    }
    31603073    m_playList.clear();
    31613074
    3162     m_helper.DeleteRecordings(list);
     3075    if (!list.empty())
     3076        m_helper.DeleteRecordings(list);
    31633077
    31643078    doClearPlaylist();
    31653079}
     
    32553169    return NULL;
    32563170}
    32573171
    3258 void PlaybackBox::UpdateProgramInfo(const ProgramInfo &pginfo)
    3259 {
    3260     // LiveTV ProgramInfo's are not in the aggregated list
    3261     ProgramList::iterator _it[2] = {
    3262         m_progLists[tr("LiveTV").toLower()].begin(), m_progLists[""].begin() };
    3263     ProgramList::iterator _end[2] = {
    3264         m_progLists[tr("LiveTV").toLower()].end(),   m_progLists[""].end()   };
    3265 
    3266     // We do not update the pathname as it may be localized
    3267     // in the remote ProgramInfo.
    3268 
    3269     for (uint i = 0; i < 2; i++)
    3270     {
    3271         ProgramList::iterator it = _it[i], end = _end[i];
    3272         for (; it != end; ++it)
    3273         {
    3274             if (pginfo.chanid     == (*it)->chanid &&
    3275                 pginfo.recstartts == (*it)->recstartts)
    3276             {
    3277                 QString pathname = (**it).pathname;
    3278                 **it = pginfo;
    3279                 (**it).pathname = pathname;
    3280                 break;
    3281             }
    3282         }
    3283     }
    3284 
    3285     // now do the cache..
    3286     m_programInfoCache.Update(pginfo);
    3287 }
    3288 
    3289 void PlaybackBox::UpdateProgramInfo(
    3290     uint chanid, const QDateTime &recstartts, uint64_t filesize)
    3291 {
    3292     // LiveTV ProgramInfo's are not in the aggregated list
    3293     ProgramList::iterator _it[2] = {
    3294         m_progLists[tr("LiveTV").toLower()].begin(), m_progLists[""].begin() };
    3295     ProgramList::iterator _end[2] = {
    3296         m_progLists[tr("LiveTV").toLower()].end(),   m_progLists[""].end()   };
    3297 
    3298     for (uint i = 0; i < 2; i++)
    3299     {
    3300         ProgramList::iterator it = _it[i], end = _end[i];
    3301         for (; it != end; ++it)
    3302         {
    3303             if (chanid     == (*it)->chanid.toUInt() &&
    3304                 recstartts == (*it)->recstartts)
    3305             {
    3306                 (*it)->filesize = filesize;
    3307                 if (filesize)
    3308                     (*it)->availableStatus = asAvailable;
    3309                 break;
    3310             }
    3311         }
    3312     }
    3313 
    3314     // now do the cache..
    3315     m_programInfoCache.UpdateFileSize(chanid, recstartts, filesize);
    3316 }
    3317 
    33183172void PlaybackBox::toggleWatched(void)
    33193173{
    33203174    MythUIButtonListItem *item = m_recordingList->GetItemCurrent();
     
    34523306    if (!pginfo)
    34533307        return;
    34543308
    3455     if (pginfo->availableStatus != asAvailable)
    3456     {
    3457         showAvailablePopup(pginfo);
    3458         return;
    3459     }
    3460 
    34613309    togglePlayListItem(pginfo);
    34623310
    34633311    if (GetFocusWidget() == m_recordingList)
     
    34693317    if (!pginfo)
    34703318        return;
    34713319
    3472     if (pginfo->availableStatus != asAvailable)
    3473     {
    3474         showAvailablePopup(pginfo);
    3475         return;
    3476     }
    3477 
    34783320    QString key = pginfo->MakeUniqueKey();
    34793321
    34803322    MythUIButtonListItem *item =
     
    36833525            else if (action == "PLAYBACK")
    36843526                playSelected(m_recordingList->GetItemCurrent());
    36853527            else if (action == "INFO")
    3686                 showActionsSelected();
     3528            {
     3529                if (GetFocusWidget() != m_groupList)
     3530                {
     3531                    ProgramInfo *pginfo = CurrentItem();
     3532                    if (pginfo)
     3533                    {
     3534                        m_helper.CheckAvailability(
     3535                            *pginfo, kCheckForMenuAction);
     3536
     3537                        if ((asPendingDelete == pginfo->availableStatus) ||
     3538                            (asPendingDelete == pginfo->availableStatus))
     3539                        {
     3540                            ShowAvailabilityPopup(*pginfo);
     3541                        }
     3542                        else
     3543                        {
     3544                            ShowActionPopup(*pginfo);
     3545                        }
     3546                    }
     3547                }
     3548            }
    36873549            else if (action == "DETAILS")
    36883550                details();
    36893551            else if (action == "CUSTOMEDIT")
     
    38203682                return;
    38213683
    38223684            m_delList = me->ExtraDataList();
     3685            for (uint i = 0; i+2 < (uint)m_delList.size(); i+=3)
     3686            {
     3687                const ProgramInfo *pginfo =
     3688                    FindProgramInUILists(
     3689                        m_delList[i+0].toUInt(),
     3690                        QDateTime::fromString(m_delList[i+1], Qt::ISODate));
     3691                if (pginfo)
     3692                    m_helper.CheckAvailability(*pginfo, kCheckForCache);
     3693            }
     3694
    38233695            bool forceDelete = m_delList[2].toUInt();
    38243696            if (!forceDelete)
    38253697                ShowDeletePopup(kForceDeleteRecording);
     
    38303702        {
    38313703            HandlePreviewEvent(me->ExtraData(0), me->ExtraData(1));
    38323704        }
     3705        else if (message == "AVAILABILITY" && me->ExtraDataCount() == 8)
     3706        {
     3707            const uint kMaxUIWaitTime = 100; // ms
     3708            QStringList list = me->ExtraDataList();
     3709            QString key = list[0];
     3710            CheckAvailabilityType cat =
     3711                (CheckAvailabilityType) list[1].toInt();
     3712            AvailableStatusType availableStatus =
     3713                (AvailableStatusType) list[2].toInt();
     3714            uint64_t fs = list[3].toULongLong();
     3715            QTime tm;
     3716            tm.setHMS(list[4].toUInt(), list[5].toUInt(),
     3717                      list[6].toUInt(), list[7].toUInt());
     3718            QTime now = QTime::currentTime();
     3719            int time_elapsed = tm.msecsTo(now);
     3720            if (time_elapsed < 0)
     3721                time_elapsed += 24 * 60 * 60 * 1000;
     3722
     3723            AvailableStatusType old_avail = availableStatus;
     3724            ProgramInfo *pginfo = FindProgramInUILists(key);
     3725            if (pginfo)
     3726            {
     3727                pginfo->filesize = max(pginfo->filesize, fs);
     3728                old_avail = pginfo->availableStatus;
     3729                pginfo->availableStatus = availableStatus;
     3730            }
     3731
     3732            if ((uint)time_elapsed >= kMaxUIWaitTime)
     3733                m_playListPlay.clear();
     3734
     3735            bool playnext = ((kCheckForPlaylistAction == cat) &&
     3736                             !m_playListPlay.empty());
     3737
     3738
     3739            if (((kCheckForPlayAction     == cat) ||
     3740                 (kCheckForPlaylistAction == cat)) &&
     3741                ((uint)time_elapsed < kMaxUIWaitTime))
     3742            {
     3743                if (asAvailable != availableStatus)
     3744                {
     3745                    if (kCheckForPlayAction == cat)
     3746                        ShowAvailabilityPopup(*pginfo);
     3747                }
     3748                else if (pginfo)
     3749                {
     3750                    playnext = false;
     3751                    Play(*pginfo, kCheckForPlaylistAction == cat);
     3752                }
     3753            }
     3754
     3755            if (playnext)
     3756            {
     3757                // failed to play this item, instead
     3758                // play the next item on the list..
     3759                QCoreApplication::postEvent(
     3760                    this, new MythEvent("PLAY_PLAYLIST"));
     3761            }
     3762
     3763            if (old_avail != availableStatus)
     3764                UpdateUIListItem(pginfo);
     3765        }
     3766        else if ((message == "PLAY_PLAYLIST") && !m_playListPlay.empty())
     3767        {
     3768            QString key = m_playListPlay.front();
     3769            m_playListPlay.pop_front();
     3770
     3771            if (!m_playListPlay.empty())
     3772            {
     3773                const ProgramInfo *pginfo =
     3774                    FindProgramInUILists(m_playListPlay.front());
     3775                if (pginfo)
     3776                    m_helper.CheckAvailability(*pginfo, kCheckForCache);
     3777            }
     3778
     3779            ProgramInfo *pginfo = FindProgramInUILists(key);
     3780            if (pginfo)
     3781                Play(*pginfo, true);
     3782        }
    38333783    }
    38343784    else
    38353785        ScheduleCommon::customEvent(event);
     
    38383788void PlaybackBox::HandleRecordingRemoveEvent(
    38393789    uint chanid, const QDateTime &recstartts)
    38403790{
    3841     ProgramInfo *pginfo = FindProgramInUILists(chanid, recstartts);
    3842     if (pginfo && ((pginfo->availableStatus != asPendingDelete) ||
    3843                    (m_currentGroup == m_watchGroupLabel)))
     3791    if (!m_programInfoCache.Remove(chanid, recstartts))
    38443792    {
    3845         m_recordingList->RemoveItem(
    3846             m_recordingList->GetItemByData(qVariantFromValue(pginfo)));
    3847         if (m_recordingList->GetCount() == 0)
    3848             m_groupList->RemoveItem(m_groupList->GetItemCurrent());
     3793        VERBOSE(VB_IMPORTANT, LOC_WARN +
     3794                QString("Failed to remove %1:%2, reloading list")
     3795                .arg(chanid).arg(recstartts.toString(Qt::ISODate)));
     3796        m_programInfoCache.ScheduleLoad();
     3797        return;
    38493798    }
    38503799
    3851     if (!m_programInfoCache.Remove(chanid, recstartts))
    3852         m_programInfoCache.ScheduleLoad();
    3853     else
    3854         ScheduleUpdateUIList();
     3800    {
     3801        ProgramInfo *tmp = CurrentItem();
     3802        if (tmp)
     3803        {
     3804            VERBOSE(VB_IMPORTANT, QString("1 CurrentItem: %1:%2, %3")
     3805                    .arg(tmp->title).arg(tmp->subtitle)
     3806                    .arg(tmp->availableStatus));
     3807        }
     3808    }
    38553809
     3810    MythUIButtonListItem *sel_item = m_groupList->GetItemCurrent();
     3811    QString groupname;
     3812    if (sel_item)
     3813        groupname = sel_item->GetData().toString();
     3814
     3815    ProgramMap::iterator git = m_progLists.begin();
     3816    while (git != m_progLists.end())
     3817    {
     3818        ProgramList::iterator pit = (*git).begin();
     3819        while (pit != (*git).end())
     3820        {
     3821            if ((*pit)->recstartts      == recstartts &&
     3822                (*pit)->chanid.toUInt() == chanid)
     3823            {
     3824                if (!git.key().isEmpty() && git.key() == groupname)
     3825                {
     3826                    MythUIButtonListItem *item_by_data =
     3827                        m_recordingList->GetItemByData(
     3828                            qVariantFromValue(*pit));
     3829                    MythUIButtonListItem *item_cur =
     3830                        m_recordingList->GetItemCurrent();
     3831
     3832                    if (item_cur && (item_by_data == item_cur))
     3833                    {
     3834                        VERBOSE(VB_IMPORTANT, "Attempting to select next");
     3835                        MythUIButtonListItem *item_next =
     3836                            m_recordingList->GetItemNext(item_cur);
     3837                        if (item_next)
     3838                        {
     3839                            VERBOSE(VB_IMPORTANT, "Selecting next");
     3840                            m_recordingList->SetItemCurrent(item_next);
     3841                        }
     3842                    }
     3843
     3844                    m_recordingList->RemoveItem(item_by_data);
     3845                }
     3846                pit = (*git).erase(pit);
     3847            }
     3848            else
     3849            {
     3850                pit++;
     3851            }
     3852        }
     3853
     3854        if ((*git).empty())
     3855        {
     3856            VERBOSE(VB_IMPORTANT, QString("Group '%1' empty").arg(git.key()));
     3857            if (!groupname.isEmpty() && (git.key() == groupname))
     3858            {
     3859                VERBOSE(VB_IMPORTANT, "Attempting to select next group");
     3860                MythUIButtonListItem *next_item =
     3861                    m_groupList->GetItemNext(sel_item);
     3862                if (next_item)
     3863                {
     3864                    VERBOSE(VB_IMPORTANT, "Selecting next group");
     3865                    m_groupList->SetItemCurrent(next_item);
     3866                }
     3867
     3868                m_groupList->RemoveItem(sel_item);
     3869
     3870                sel_item = next_item;
     3871                groupname = "";
     3872                if (sel_item)
     3873                    groupname = sel_item->GetData().toString();
     3874            }
     3875            git = m_progLists.erase(git);
     3876        }
     3877        else
     3878            git++;
     3879    }
     3880
     3881    {
     3882        ProgramInfo *tmp = CurrentItem();
     3883        if (tmp)
     3884        {
     3885            VERBOSE(VB_IMPORTANT, QString("1 Selected Item: %1:%2, %3")
     3886                    .arg(tmp->title).arg(tmp->subtitle)
     3887                    .arg(tmp->availableStatus));
     3888        }
     3889    }
     3890
    38563891    m_helper.ForceFreeSpaceUpdate();
    38573892}
    38583893
     
    38643899
    38653900void PlaybackBox::HandleUpdateProgramInfoEvent(const ProgramInfo &evinfo)
    38663901{
    3867     ProgramInfo *dst = FindProgramInUILists(evinfo);
    3868     QString old_recgroup;
    3869     if (dst)
    3870         old_recgroup = dst->recgroup;
     3902    QString old_recgroup = m_programInfoCache.GetRecGroup(
     3903        evinfo.chanid.toUInt(), evinfo.recstartts);
    38713904
    3872     UpdateProgramInfo(evinfo);
     3905    m_programInfoCache.Update(evinfo);
    38733906
    3874     // If the program is not in the the recording lists, then it
    3875     // is either a program that was just removed from the "LiveTV"
    3876     // recording list and should possibly be displayed now, or it
    3877     // is still in the "LiveTV" recording group and we're not
    3878     // displaying programs in that group. Handle appropriately..
    3879     if (!dst)
     3907    // If the recording group has changed, reload lists from the recently
     3908    // updated cache; if not, only update UI for the updated item
     3909    if (evinfo.recgroup == old_recgroup)
    38803910    {
    3881         if (evinfo.recgroup != "LiveTV")
    3882             ScheduleUpdateUIList();
     3911        ProgramInfo *dst = FindProgramInUILists(evinfo);
     3912        if (dst)
     3913            UpdateUIListItem(dst);
    38833914        return;
    38843915    }
    38853916
    3886     // If the recording group has changed, reload lists from the recently
    3887     // updated cache; if not, only update UI for the updated item
    3888     if (dst->recgroup != old_recgroup)
    3889         ScheduleUpdateUIList();
    3890     else
    3891         UpdateUIListItem(dst);
     3917    ScheduleUpdateUIList();
    38923918}
    38933919
    38943920void PlaybackBox::HandleUpdateProgramInfoFileSizeEvent(
    38953921    uint chanid, const QDateTime &recstartts, uint64_t filesize)
    38963922{
    3897     UpdateProgramInfo(chanid, recstartts, filesize);
     3923    m_programInfoCache.UpdateFileSize(chanid, recstartts, filesize);
    38983924
    38993925    ProgramInfo *dst = FindProgramInUILists(chanid, recstartts);
    39003926    if (dst)
     
    41354161void PlaybackBox::ShowRecGroupChanger(bool use_playlist)
    41364162{
    41374163    m_op_on_playlist = use_playlist;
     4164
     4165    ProgramInfo *pginfo = NULL;
     4166    if (use_playlist)
     4167    {
     4168        if (!m_playList.empty())
     4169            pginfo = FindProgramInUILists(m_playList[0]);
     4170    }
     4171    else
     4172        pginfo = CurrentItem();
     4173
     4174    if (!pginfo)
     4175        return;
     4176
    41384177    MSqlQuery query(MSqlQuery::InitCon());
    41394178    query.prepare(
    41404179        "SELECT recgroup, COUNT(title) FROM recorded "
    41414180        "WHERE deletepending = 0 GROUP BY recgroup ORDER BY recgroup");
    41424181
    4143     QStringList groupNames;
    4144     QStringList displayNames;
    4145     QString selected;
     4182    QStringList displayNames(tr("Add New"));
     4183    QStringList groupNames("addnewgroup");
    41464184
    4147     groupNames.append("addnewgroup");
    4148     displayNames.append(tr("Add New"));
     4185    if (!query.exec())
     4186        return;
    41494187
    4150     if (query.exec())
     4188    while (query.next())
    41514189    {
    4152         QString itemStr;
    4153         QString dispGroup;
    4154         while (query.next())
    4155         {
    4156             dispGroup = query.value(0).toString();
     4190        QString dispGroup = query.value(0).toString();
     4191        groupNames.push_back(dispGroup);
    41574192
    4158             groupNames.append(dispGroup);
     4193        if (dispGroup == "Default")
     4194            dispGroup = tr("Default");
     4195        else if (dispGroup == "LiveTV")
     4196            dispGroup = tr("LiveTV");
     4197        else if (dispGroup == "Deleted")
     4198            dispGroup = tr("Deleted");
    41594199
    4160             if (dispGroup == "Default")
    4161                 dispGroup = tr("Default");
    4162             else if (dispGroup == "LiveTV")
    4163                 dispGroup = tr("LiveTV");
    4164             else if (dispGroup == "Deleted")
    4165                 dispGroup = tr("Deleted");
     4200        QString itemStr = tr("item(s)", "", query.value(1).toInt());
    41664201
    4167             itemStr = tr("item(s)", "", query.value(1).toInt());
    4168 
    4169             displayNames.append(QString("%1 [%2 %3]").arg(dispGroup)
    4170                               .arg(query.value(1).toInt()).arg(itemStr));
    4171         }
     4202        displayNames.push_back(
     4203            QString("%1 [%2 %3]")
     4204            .arg(dispGroup).arg(query.value(1).toInt()).arg(itemStr));
    41724205    }
    41734206
    4174     ProgramInfo *pginfo = CurrentItem();
    4175     selected = pginfo->recgroup;
     4207    QString label = tr("Select Recording Group") +
     4208        CreateProgramInfoString(*pginfo);
    41764209
    4177     QString label = tr("Select Recording Group");
     4210    GroupSelector *rgChanger = new GroupSelector(
     4211        m_popupStack, label, displayNames, groupNames, pginfo->recgroup);
    41784212
    4179     popupString(pginfo, label);
    4180 
    4181     GroupSelector *rgChanger = new GroupSelector(m_popupStack, label,
    4182                                                  displayNames, groupNames,
    4183                                                  selected);
    4184 
    41854213    if (rgChanger->Create())
    41864214    {
    41874215        connect(rgChanger, SIGNAL(result(QString)), SLOT(setRecGroup(QString)));
     
    41954223void PlaybackBox::ShowPlayGroupChanger(bool use_playlist)
    41964224{
    41974225    m_op_on_playlist = use_playlist;
    4198     QStringList groupNames;
    4199     QStringList displayNames;
    4200     QString selected;
    42014226
    4202     displayNames.append(tr("Default"));
    4203     groupNames.append("Default");
    4204 
    4205     QStringListIterator it(PlayGroup::GetNames());
    4206     while (it.hasNext())
     4227    ProgramInfo *pginfo = NULL;
     4228    if (use_playlist)
    42074229    {
    4208         QString group = it.next();
    4209         displayNames.append(group);
    4210         groupNames.append(group);
     4230        if (!m_playList.empty())
     4231            pginfo = FindProgramInUILists(m_playList[0]);
    42114232    }
     4233    else
     4234        pginfo = CurrentItem();
    42124235
    4213     ProgramInfo *pginfo = CurrentItem();
    4214     selected = pginfo->playgroup;
     4236    if (!pginfo)
     4237        return;
    42154238
    4216     QString label = tr("Select Playback Group");
     4239    QStringList groupNames(tr("Default"));
     4240    QStringList displayNames("Default");
    42174241
    4218     popupString(pginfo, label);
     4242    QStringList list = PlayGroup::GetNames();
     4243    QStringList::const_iterator it = list.begin();
     4244    for (; it != list.end(); ++it)
     4245    {
     4246        displayNames.push_back(*it);
     4247        groupNames.push_back(*it);
     4248    }
    42194249
     4250    QString label = tr("Select Playback Group") +
     4251        CreateProgramInfoString(*pginfo);
     4252
    42204253    GroupSelector *pgChanger = new GroupSelector(m_popupStack, label,
    42214254                                                 displayNames, groupNames,
    4222                                                  selected);
     4255                                                 pginfo->playgroup);
    42234256
    42244257    if (pgChanger->Create())
    42254258    {
     
    43624395    RecordingInfo ri(*p);
    43634396    ri.ApplyRecordRecGroupChange(newRecGroup);
    43644397    *p = ri;
     4398    UpdateUILists();
    43654399}
    43664400
    43674401void PlaybackBox::setPlayGroup(QString newPlayGroup)
  • programs/mythfrontend/playbackboxhelper.h

     
    3535typedef QMap<QString,PreviewGenState> PreviewMap;
    3636typedef QMap<QString,QDateTime>       FileTimeStampMap;
    3737
     38typedef enum CheckAvailabilityType {
     39    kCheckForCache,
     40    kCheckForMenuAction,
     41    kCheckForPlayAction,
     42    kCheckForPlaylistAction,
     43} CheckAvailabilityType;
     44
    3845class PlaybackBoxHelper : public QThread
    3946{
    4047    friend class PBHEventHandler;
     
    5158        uint chanid, const QDateTime &recstartts, bool forceDelete);
    5259    void DeleteRecordings(const QStringList&);
    5360    void UndeleteRecording(uint chanid, const QDateTime &recstartts);
     61    void CheckAvailability(const ProgramInfo&,
     62                           CheckAvailabilityType cat = kCheckForCache);
    5463    void GetPreviewImage(const ProgramInfo&);
    5564
    5665    virtual void run(void);      // QThread
  • programs/mythfrontend/playbackboxhelper.cpp

     
    131131                }
    132132            }
    133133        }
     134        else if (me->Message() == "CHECK_AVAILABILITY")
     135        {
     136            CheckAvailabilityType cat = kCheckForCache;
     137            QTime tm;
     138            if (me->ExtraDataCount() >= 5)
     139            {
     140                cat = (CheckAvailabilityType) me->ExtraData(0).toUInt();
     141                tm.setHMS(
     142                    me->ExtraData(1).toUInt(),
     143                    me->ExtraData(2).toUInt(),
     144                    me->ExtraData(3).toUInt(),
     145                    me->ExtraData(4).toUInt());
     146            }
     147            ProgramInfo evinfo;
     148            if (!evinfo.FromStringList(me->ExtraDataList(), 5))
     149                return true;
     150
     151            AvailableStatusType availableStatus = asAvailable;
     152            // Note IsFileReadable() implicitly calls GetPlaybackURL
     153            // when necessary, we rely on this.
     154            if (!evinfo.IsFileReadable())
     155            {
     156                VERBOSE(VB_IMPORTANT, LOC_ERR +
     157                        QString("CHECK_AVAILABILITY '%1' "
     158                                "file not found")
     159                        .arg(evinfo.pathname));
     160                availableStatus = asFileNotFound;
     161            }
     162            else if (0 == evinfo.filesize)
     163            {
     164                evinfo.filesize = evinfo.GetFilesize();
     165                if (0 == evinfo.filesize)
     166                {
     167                    availableStatus = (evinfo.recstatus == rsRecording) ?
     168                        asNotYetAvailable : asZeroByte;
     169                }
     170            }
     171
     172            QStringList list;
     173            list.push_back(evinfo.MakeUniqueKey());
     174            list.push_back(QString::number((int)cat));
     175            list.push_back(QString::number((int)availableStatus));
     176            list.push_back(QString::number(evinfo.filesize));
     177            list.push_back(QString::number(tm.hour()));
     178            list.push_back(QString::number(tm.minute()));
     179            list.push_back(QString::number(tm.second()));
     180            list.push_back(QString::number(tm.msec()));
     181            MythEvent *e = new MythEvent("AVAILABILITY", list);
     182            QCoreApplication::postEvent(m_pbh.m_listener, e);
     183        }
    134184    }
    135185
    136186    return QObject::event(e);
     
    258308    return m_freeSpaceUsedMB;
    259309}
    260310
     311void PlaybackBoxHelper::CheckAvailability(
     312    const ProgramInfo &pginfo, CheckAvailabilityType cat)
     313{
     314    QTime tm = QTime::currentTime();
     315    QStringList list(QString::number((int)cat));
     316    list.push_back(QString::number(tm.hour()));
     317    list.push_back(QString::number(tm.minute()));
     318    list.push_back(QString::number(tm.second()));
     319    list.push_back(QString::number(tm.msec()));
     320    pginfo.ToStringList(list);
     321    MythEvent *e = new MythEvent("CHECK_AVAILABILITY", list);
     322    QCoreApplication::postEvent(m_eventHandler, e);       
     323}
     324
    261325void PlaybackBoxHelper::GetPreviewImage(const ProgramInfo &pginfo)
    262326{
    263327    QStringList extra;
  • programs/mythfrontend/programinfocache.h

     
    3838    bool Update(const ProgramInfo&);
    3939    bool UpdateFileSize(uint chanid, const QDateTime &recstartts,
    4040                        uint64_t filesize);
     41    QString GetRecGroup(uint chanid, const QDateTime &recstartts) const;
    4142    void GetOrdered(vector<ProgramInfo*> &list, bool newest_first = false);
    4243    /// \note This must only be called from the UI thread.
    4344    bool empty(void) const { return m_cache.empty(); }
  • programs/mythfrontend/programinfocache.cpp

     
    185185    return it != m_cache.end();
    186186}
    187187
     188/** \brief Returns the ProgramInfo::recgroup or an empty string if not found.
     189 *  \note This must only be called from the UI thread.
     190 */
     191QString ProgramInfoCache::GetRecGroup(
     192    uint chanid, const QDateTime &recstartts) const
     193{
     194    QMutexLocker locker(&m_lock);
     195
     196    Cache::const_iterator it = m_cache.find(PICKey(chanid,recstartts));
     197
     198    QString recgroup;
     199    if (it != m_cache.end())
     200        recgroup = it->second->recgroup;
     201
     202    return recgroup;
     203}
     204
    188205/** \brief Adds a ProgramInfo to the cache.
    189206 *  \note This must only be called from the UI thread.
    190207 */
  • programs/mythfrontend/playbackbox.h

     
    142142    void upcoming();
    143143    void details();
    144144    void StopSelected(void);
    145     void showActionsSelected();
    146145    void showMetadataEditor();
    147146    void showGroupFilter();
    148147    void showRecGroupPasswordChanger();
    149     MythDialogBox *createPopupMenu(const QString &title);
    150     MythDialogBox *createProgramPopupMenu(const QString &title,
    151                                           ProgramInfo *pginfo = NULL);
    152     MythDialogBox *createPlaylistPopupMenu();
    153148    void showPlayFromPopup();
    154149    void showRecordingPopup();
    155150    void showJobPopup();
     
    263258
    264259  private:
    265260    bool UpdateUILists(void);
     261    void UpdateUIGroupList(const QStringList &groupPreferences);
     262
    266263    void UpdateProgressBar(void);
    267264
    268265    QString cutDown(const QString &, QFont *, int);
    269266
    270     bool play(ProgramInfo *rec, bool inPlaylist = false);
    271     void showActions(ProgramInfo *);
     267    bool Play(const ProgramInfo &rec, bool inPlaylist);
    272268    ProgramInfo *CurrentItem(void);
    273269
    274270    void togglePlayListItem(ProgramInfo *pginfo);
     
    286282    void RemoveProgram(uint chanid, const QDateTime &recstartts,
    287283                       bool forgetHistory, bool forceMetadataDelete);
    288284    void ShowDeletePopup(DeletePopupType);
    289     void showActionPopup(ProgramInfo *program);
    290     void showFileNotFoundActionPopup(ProgramInfo *program);
    291     void popupString(ProgramInfo *program, QString &message);
     285    void ShowAvailabilityPopup(const ProgramInfo&);
     286    void ShowActionPopup(const ProgramInfo&);
    292287
    293     void showAvailablePopup(ProgramInfo *rec);
    294 
    295288    QString getRecGroupPassword(const QString &recGroup);
    296289    void fillRecGroupPasswordCache(void);
    297290
     
    302295
    303296    bool IsUsageUIVisible(void) const;
    304297
    305     void updateGroupList();
    306298    void updateIcons(const ProgramInfo *pginfo = NULL);
    307299    void UpdateUsageUI(void);
    308300    void updateGroupInfo(const QString &groupname, const QString &grouplabel);
    309     void UpdateProgramInfo(const ProgramInfo &pginfo);
    310     void UpdateProgramInfo(
    311         uint chanid, const QDateTime &recstartts, uint64_t filesize);
    312301
    313302    void UpdateUIListItem(
    314303        ProgramInfo *ProgramInfo_pointer_from_FindProgramInUILists);
     
    326315
    327316    void ShowMenu(void);
    328317
     318    bool CreatePopupMenu(const QString &title);
     319    bool CreatePopupMenu(const QString &title, const ProgramInfo &pginfo)
     320        { return CreatePopupMenu(title + CreateProgramInfoString(pginfo)); }
     321    bool CreatePopupMenuPlaylist(void);
     322
     323    QString CreateProgramInfoString(const ProgramInfo &program) const;
     324
     325  private:
    329326    MythUIButtonList *m_groupList;
    330327    MythUIButtonList *m_recordingList;
    331328
     
    405402    // Other state
    406403    /// Program[s] currently selected for deletion
    407404    QStringList m_delList;
    408     /// Program currently selected during an update
    409     ProgramInfo *m_currentItem;
    410405    /// Group currently selected
    411406    QString m_currentGroup;
    412407
    413408    // Play List support
    414409    QStringList         m_playList;   ///< list of selected items "play list"
    415410    bool                m_op_on_playlist;
     411    QStringList         m_playListPlay; ///< list of items being played.
    416412
    417413    ProgramInfoCache    m_programInfoCache;
    418414