• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files

playbackbox.cpp

Go to the documentation of this file.
00001 #include <qpushbutton.h>
00002 #include <qbuttongroup.h>
00003 #include <qlabel.h>
00004 #include <qcursor.h>
00005 #include <qaccel.h>
00006 #include <qlistview.h>
00007 #include <qdatetime.h>
00008 #include <qprogressbar.h>
00009 #include <qlayout.h>
00010 #include <qapplication.h>
00011 #include <qtimer.h>
00012 #include <qimage.h>
00013 #include <qpainter.h>
00014 #include <qheader.h>
00015 #include <qfile.h>
00016 #include <qfileinfo.h>
00017 #include <qsqldatabase.h>
00018 #include <qmap.h>
00019 #include <qwaitcondition.h>
00020 
00021 #include <cmath>
00022 #include <unistd.h>
00023 #include <stdlib.h>
00024 
00025 #include <algorithm>
00026 #include <iostream>
00027 using namespace std;
00028 
00029 #include "playbackbox.h"
00030 #include "proglist.h"
00031 #include "tv.h"
00032 #include "oldsettings.h"
00033 #include "NuppelVideoPlayer.h"
00034 
00035 #include "exitcodes.h"
00036 #include "mythcontext.h"
00037 #include "mythdbcon.h"
00038 #include "programinfo.h"
00039 #include "scheduledrecording.h"
00040 #include "remoteutil.h"
00041 #include "lcddevice.h"
00042 #include "previewgenerator.h"
00043 #include "playgroup.h"
00044 #include "customedit.h"
00045 
00046 #define LOC QString("PlaybackBox: ")
00047 #define LOC_ERR QString("PlaybackBox Error: ")
00048 
00049 #define REC_CAN_BE_DELETED(rec) \
00050     ((((rec)->programflags & FL_INUSEPLAYING) == 0) && \
00051      ((((rec)->programflags & FL_INUSERECORDING) == 0) || \
00052       ((rec)->recgroup != "LiveTV")))
00053 
00054 #define USE_PREV_GEN_THREAD
00055 
00056 QWaitCondition pbbIsVisibleCond;
00057 
00058 const uint PreviewGenState::maxAttempts     = 5;
00059 const uint PreviewGenState::minBlockSeconds = 60;
00060 
00061 const uint PlaybackBox::previewGeneratorMaxRunning = 2;
00062 
00063 static int comp_programid(ProgramInfo *a, ProgramInfo *b)
00064 {
00065     if (a->programid == b->programid)
00066         return (a->recstartts < b->recstartts ? 1 : -1);
00067     else
00068         return (a->programid < b->programid ? 1 : -1);
00069 }
00070 
00071 static int comp_programid_rev(ProgramInfo *a, ProgramInfo *b)
00072 {
00073     if (a->programid == b->programid)
00074         return (a->recstartts > b->recstartts ? 1 : -1);
00075     else
00076         return (a->programid > b->programid ? 1 : -1);
00077 }
00078 
00079 static int comp_originalAirDate(ProgramInfo *a, ProgramInfo *b)
00080 {
00081     QDate dt1, dt2;
00082 
00083     if (a->hasAirDate)
00084         dt1 = a->originalAirDate;
00085     else
00086         dt1 = a->startts.date();
00087 
00088     if (b->hasAirDate)
00089         dt2 = b->originalAirDate;
00090     else
00091         dt2 = b->startts.date();
00092 
00093     if (dt1 == dt2)
00094         return (a->recstartts < b->recstartts ? 1 : -1);
00095     else
00096         return (dt1 < dt2 ? 1 : -1);
00097 }
00098 
00099 static int comp_originalAirDate_rev(ProgramInfo *a, ProgramInfo *b)
00100 {
00101     QDate dt1, dt2;
00102 
00103     if (a->hasAirDate)
00104         dt1 = a->originalAirDate;
00105     else
00106         dt1 = a->startts.date();
00107 
00108     if (b->hasAirDate)
00109         dt2 = b->originalAirDate;
00110     else
00111         dt2 = b->startts.date();
00112 
00113     if (dt1 == dt2)
00114         return (a->recstartts > b->recstartts ? 1 : -1);
00115     else
00116         return (dt1 > dt2 ? 1 : -1);
00117 }
00118 
00119 static int comp_recpriority2(ProgramInfo *a, ProgramInfo *b)
00120 {
00121     if (a->recpriority2 == b->recpriority2)
00122         return (a->recstartts < b->recstartts ? 1 : -1);
00123     else
00124         return (a->recpriority2 < b->recpriority2 ? 1 : -1);
00125 }
00126 
00127 static PlaybackBox::ViewMask viewMaskToggle(PlaybackBox::ViewMask mask,
00128         PlaybackBox::ViewMask toggle)
00129 {
00130     // can only toggle a single bit at a time
00131     if ((mask & toggle))
00132         return (PlaybackBox::ViewMask)(mask & ~toggle);
00133     return (PlaybackBox::ViewMask)(mask | toggle);
00134 }
00135 
00136 static QString sortTitle(QString title, PlaybackBox::ViewMask viewmask,
00137         PlaybackBox::ViewTitleSort titleSort, int recpriority)
00138 {
00139     if (title == "")
00140         return title;
00141 
00142     QRegExp prefixes = QObject::tr("^(The |A |An )");
00143     QString sTitle = title;
00144 
00145     sTitle.remove(prefixes);
00146     if (viewmask == PlaybackBox::VIEW_TITLES &&
00147             titleSort == PlaybackBox::TitleSortRecPriority)
00148     {
00149         // Also incorporate recpriority (reverse numeric sort). In
00150         // case different episodes of a recording schedule somehow
00151         // have different recpriority values (e.g., manual fiddling
00152         // with database), the title will appear once for each
00153         // distinct recpriority value among its episodes.
00154         //
00155         // Deal with QMap sorting. Positive recpriority values have a
00156         // '+' prefix (QMap alphabetically sorts before '-'). Positive
00157         // recpriority values are "inverted" by substracting them from
00158         // 1000, so that high recpriorities are sorted first (QMap
00159         // alphabetically). For example:
00160         //
00161         //      recpriority =>  sort key
00162         //          95          +905
00163         //          90          +910
00164         //          89          +911
00165         //           1          +999
00166         //           0          -000
00167         //          -5          -005
00168         //         -10          -010
00169         //         -99          -099
00170 
00171         QString sortprefix;
00172         if (recpriority > 0)
00173             sortprefix.sprintf("+%03u", 1000 - recpriority);
00174         else
00175             sortprefix.sprintf("-%03u", -recpriority);
00176 
00177         sTitle = sortprefix + "-" + sTitle;
00178     }
00179     return sTitle;
00180 }
00181 
00182 static int comp_recordDate(ProgramInfo *a, ProgramInfo *b)
00183 {
00184     if (a->startts.date() == b->startts.date())
00185         return (a->recstartts < b->recstartts ? 1 : -1);
00186     else
00187         return (a->startts.date() < b->startts.date() ? 1 : -1);
00188 }
00189 
00190 static int comp_recordDate_rev(ProgramInfo *a, ProgramInfo *b)
00191 {
00192     if (a->startts.date() == b->startts.date())
00193         return (a->recstartts > b->recstartts ? 1 : -1);
00194     else
00195         return (a->startts.date() > b->startts.date() ? 1 : -1);
00196 }
00197 
00198 
00199 ProgramInfo *PlaybackBox::RunPlaybackBox(void * player, bool showTV)
00200 {
00201     ProgramInfo *nextProgram = NULL;
00202     qApp->lock();
00203 
00204     PlaybackBox *pbb = new PlaybackBox(PlaybackBox::Play,
00205             gContext->GetMainWindow(), "tvplayselect", (TV *)player, showTV);
00206     pbb->Show();
00207 
00208     qApp->unlock();
00209     pbbIsVisibleCond.wait();
00210 
00211     if (pbb->getSelected())
00212         nextProgram = new ProgramInfo(*pbb->getSelected());
00213 
00214     delete pbb;
00215 
00216     return nextProgram;
00217 }
00218 
00219 PlaybackBox::PlaybackBox(BoxType ltype, MythMainWindow *parent,
00220                          const char *name, TV *player, bool showTV)
00221     : MythDialog(parent, name),
00222       // Settings
00223       type(ltype),
00224       formatShortDate("M/d"),           formatLongDate("ddd MMMM d"),
00225       formatTime("h:mm AP"),
00226       titleView(true),                  useCategories(false),
00227       useRecGroups(false),              watchListAutoExpire(false),
00228       watchListMaxAge(60),              watchListBlackOut(2),
00229       groupnameAsAllProg(false),
00230       arrowAccel(true),                 ignoreKeyPressEvents(false),
00231       listOrder(1),                     listsize(0),
00232       // Recording Group settings
00233       groupDisplayName(tr("All Programs")),
00234       recGroup("All Programs"),
00235       recGroupPassword(""),             curGroupPassword(""),
00236       watchGroupName(" " + tr("Watch List")),
00237       watchGroupLabel(watchGroupName.lower()),
00238       viewMask(VIEW_TITLES),
00239       // Theme parsing
00240       theme(new XMLParse()),
00241       // Non-volatile drawing variables
00242       drawTransPixmap(NULL),            drawPopupSolid(true),
00243       drawPopupFgColor(Qt::white),      drawPopupBgColor(Qt::black),
00244       drawPopupSelColor(Qt::green),
00245       drawTotalBounds(0, 0, size().width(), size().height()),
00246       drawListBounds(0, 0, 0, 0),       drawInfoBounds(0, 0, 0, 0),
00247       drawGroupBounds(0, 0, 0, 0),      drawUsageBounds(0, 0, 0, 0),
00248       drawVideoBounds(0, 0, 0, 0),      blackholeBounds(0, 0, 0, 0),
00249       drawCurGroupBounds(0, 0, 0, 0),
00250       // General popup support
00251       popup(NULL),                      expectingPopup(false),
00252       // Recording Group popup support
00253       recGroupLastItem(0),              recGroupChooserPassword(""),
00254       recGroupPopup(NULL),              recGroupListBox(NULL),
00255       recGroupLineEdit(NULL),           recGroupLineEdit1(NULL),
00256       recGroupOldPassword(NULL),        recGroupNewPassword(NULL),
00257       recGroupOkButton(NULL),
00258       // Main Recording List support
00259       fillListTimer(new QTimer(this)),  fillListFromCache(false),
00260       connected(false),
00261       titleIndex(0),                    progIndex(0),
00262       progsInDB(0),
00263       // Other state
00264       curitem(NULL),                    delitem(NULL),
00265       progCache(NULL),                  playingSomething(false),
00266       // Selection state variables
00267       haveGroupInfoSet(false),          inTitle(false),
00268       leftRight(false), playbackVideoContainer(false),
00269       // Free disk space tracking
00270       freeSpaceNeedsUpdate(true),       freeSpaceTimer(new QTimer(this)),
00271       freeSpaceTotal(0),                freeSpaceUsed(0),
00272       // Volatile drawing variables
00273       paintSkipCount(0),                paintSkipUpdate(false),
00274       // Preview Video Variables
00275       previewVideoNVP(NULL),            previewVideoRingBuf(NULL),
00276       previewVideoRefreshTimer(new QTimer(this)),
00277       previewVideoBrokenRecId(0),       previewVideoState(kStopped),
00278       previewVideoStartTimerOn(false),  previewVideoEnabled(false),
00279       previewVideoPlaying(false),       previewVideoThreadRunning(false),
00280       previewVideoKillState(kDone),
00281       // Preview Image Variables
00282       previewPixmapEnabled(false),      previewPixmap(NULL),
00283       previewSuspend(false),            previewChanid(""),
00284       previewGeneratorRunning(0),
00285       // Network Control Variables
00286       underNetworkControl(false),
00287       m_player(NULL)
00288 {
00289     formatShortDate    = gContext->GetSetting("ShortDateFormat", "M/d");
00290     formatLongDate     = gContext->GetSetting("DateFormat", "ddd MMMM d");
00291     formatTime         = gContext->GetSetting("TimeFormat", "h:mm AP");
00292     recGroup           = gContext->GetSetting("DisplayRecGroup","All Programs");
00293     int pbOrder        = gContext->GetNumSetting("PlayBoxOrdering", 1);
00294     // Split out sort order modes, wacky order for backward compatibility
00295     listOrder = (pbOrder >> 1) ^ (allOrder = pbOrder & 1);
00296     watchListStart     = gContext->GetNumSetting("PlaybackWLStart", 0);
00297     watchListAutoExpire= gContext->GetNumSetting("PlaybackWLAutoExpire", 0);
00298     watchListMaxAge    = gContext->GetNumSetting("PlaybackWLMaxAge", 60);
00299     watchListBlackOut  = gContext->GetNumSetting("PlaybackWLBlackOut", 2);
00300     groupnameAsAllProg = gContext->GetNumSetting("DispRecGroupAsAllProg", 0);
00301     arrowAccel         = gContext->GetNumSetting("UseArrowAccels", 1);
00302     inTitle            = gContext->GetNumSetting("PlaybackBoxStartInTitle", 0);
00303     if (!player)
00304         previewVideoEnabled =gContext->GetNumSetting("PlaybackPreview");
00305     previewPixmapEnabled=gContext->GetNumSetting("GeneratePreviewPixmaps");
00306     previewFromBookmark= gContext->GetNumSetting("PreviewFromBookmark");
00307     drawTransPixmap    = gContext->LoadScalePixmap("trans-backup.png");
00308     if (!drawTransPixmap)
00309         drawTransPixmap = new QPixmap();
00310 
00311     bool displayCat  = gContext->GetNumSetting("DisplayRecGroupIsCategory", 0);
00312     int  initialFilt = gContext->GetNumSetting("QueryInitialFilter", 0);
00313 
00314     viewMask = (ViewMask)gContext->GetNumSetting(
00315             "DisplayGroupDefaultViewMask", VIEW_TITLES);
00316 
00317     if (gContext->GetNumSetting("PlaybackWatchList", 1))
00318         viewMask = (ViewMask)(viewMask | VIEW_WATCHLIST);
00319 
00320     progLists[""];
00321     titleList << "";
00322     playList.clear();
00323 
00324     if (player)
00325     {
00326         m_player = player;
00327         if (m_player->getCurrentProgram() && m_player->IsPlaying())
00328             recGroup = m_player->getCurrentProgram()->recgroup;
00329     }
00330     // recording group stuff
00331     recGroupType.clear();
00332     recGroupType[recGroup] = (displayCat) ? "category" : "recgroup";
00333     if (groupnameAsAllProg)
00334     {
00335         groupDisplayName = recGroup;
00336         if ((recGroup == "All Programs") ||
00337             (recGroup == "Default") ||
00338             (recGroup == "LiveTV") ||
00339             (recGroup == "Deleted"))
00340         {
00341             groupDisplayName = tr(recGroup);
00342         }
00343     }
00344 
00345     if (!m_player)
00346         recGroupPassword = getRecGroupPassword(recGroup);
00347 
00348     // theme stuff
00349     theme->SetWMult(wmult);
00350     theme->SetHMult(hmult);
00351     if (m_player && m_player->IsRunning() && showTV &&
00352         theme->LoadTheme(xmldata,"playback-video"))
00353     {
00354         playbackVideoContainer = true;
00355         previewPixmapEnabled = false;
00356     }
00357     else
00358         theme->LoadTheme(xmldata,"playback");
00359 
00360     LoadWindow(xmldata);
00361 
00362     EmbedTVWindow();
00363 
00364     LayerSet *container = theme->GetSet("selector");
00365     UIListType *listtype = NULL;
00366     if (container)
00367     {
00368         listtype = (UIListType *)container->GetType("showing");
00369         if (listtype)
00370             listsize = listtype->GetItems();
00371     }
00372     else
00373     {
00374         QString btn0 = QObject::tr("Failed to get selector object");
00375         QString btn1 = QObject::tr(
00376             "Myth could not locate the selector object within your theme.\n"
00377             "Please make sure that your ui.xml is valid.\n"
00378             "\n"
00379             "Myth will now exit.");
00380 
00381         MythPopupBox::showOkPopup(gContext->GetMainWindow(), btn0, btn1);
00382 
00383         VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to get selector object.");
00384         exit(FRONTEND_BUGGY_EXIT_NO_SELECTOR);
00385         return;
00386     }
00387 
00388     if (theme->GetSet("group_info") &&
00389         gContext->GetNumSetting("ShowGroupInfo", 0) == 1)
00390     {
00391         haveGroupInfoSet = true;
00392         if (listtype)
00393             listtype->ShowSelAlways(false);
00394     }
00395 
00396     // initially fill the list
00397     connected = FillList();
00398 
00399     // connect up timers...
00400     connect(previewVideoRefreshTimer, SIGNAL(timeout()),
00401             this,                     SLOT(timeout()));
00402     connect(freeSpaceTimer,           SIGNAL(timeout()),
00403             this,                     SLOT(setUpdateFreeSpace()));
00404     connect(fillListTimer,            SIGNAL(timeout()),
00405             this,                     SLOT(listChanged()));
00406 
00407     // preview video & preview pixmap init
00408     previewVideoRefreshTimer->start(500);
00409     previewStartts = QDateTime::currentDateTime();
00410 
00411     // misc setup
00412     updateBackground();
00413     setNoErase();
00414     gContext->addListener(this);
00415 
00416     if (!m_player && ((!recGroupPassword.isEmpty()) ||
00417         ((titleList.count() <= 1) && (progsInDB > 0)) ||
00418         (initialFilt)))
00419     {
00420         recGroup = "";
00421         showRecGroupChooser();
00422     }
00423 
00424     gContext->addCurrentLocation((type == Delete)? "DeleteBox":"PlaybackBox");
00425 }
00426 
00427 PlaybackBox::~PlaybackBox(void)
00428 {
00429     gContext->removeListener(this);
00430     gContext->removeCurrentLocation();
00431 
00432     if (!m_player)
00433         killPlayerSafe();
00434 
00435     if (previewVideoRefreshTimer)
00436     {
00437         previewVideoRefreshTimer->disconnect(this);
00438         previewVideoRefreshTimer->deleteLater();
00439         previewVideoRefreshTimer = NULL;
00440     }
00441 
00442     if (fillListTimer)
00443     {
00444         fillListTimer->disconnect(this);
00445         fillListTimer->deleteLater();
00446         fillListTimer = NULL;
00447     }
00448 
00449     if (freeSpaceTimer)
00450     {
00451         freeSpaceTimer->disconnect(this);
00452         freeSpaceTimer->deleteLater();
00453         freeSpaceTimer = NULL;
00454     }
00455 
00456     if (theme)
00457     {
00458         delete theme;
00459         theme = NULL;
00460     }
00461 
00462     if (drawTransPixmap)
00463     {
00464         delete drawTransPixmap;
00465         drawTransPixmap = NULL;
00466     }
00467 
00468     if (curitem)
00469     {
00470         delete curitem;
00471         curitem = NULL;
00472     }
00473 
00474     if (delitem)
00475     {
00476         delete delitem;
00477         delitem = NULL;
00478     }
00479 
00480     clearProgramCache();
00481 
00482     // disconnect preview generators
00483     QMutexLocker locker(&previewGeneratorLock);
00484     PreviewMap::iterator it = previewGenerator.begin();
00485     for (;it != previewGenerator.end(); ++it)
00486     {
00487         if ((*it).gen)
00488             (*it).gen->disconnectSafe();
00489     }
00490 
00491     // free preview pixmap after preview generators are
00492     // no longer telling us about any new previews.
00493     if (previewPixmap)
00494     {
00495         delete previewPixmap;
00496         previewPixmap = NULL;
00497     }
00498 }
00499 
00500 DialogCode PlaybackBox::exec(void)
00501 {
00502     if (recGroup != "")
00503         return MythDialog::exec();
00504     else if (gContext->GetNumSetting("QueryInitialFilter", 0) == 0)
00505     {
00506         recGroup = "All Programs";
00507         showRecGroupChooser();
00508         return MythDialog::exec();
00509     }
00510 
00511     return kDialogCodeRejected;
00512 }
00513 
00514 /* blocks until playing has stopped */
00515 void PlaybackBox::killPlayerSafe(void)
00516 {
00517     QMutexLocker locker(&previewVideoKillLock);
00518 
00519     // Don't process any keys while we are trying to make the nvp stop.
00520     // Qt's setEnabled(false) doesn't work, because of LIRC events...
00521     ignoreKeyPressEvents = true;
00522 
00523     while (previewVideoState != kKilled && previewVideoState != kStopped &&
00524            previewVideoThreadRunning)
00525     {
00526         // Make sure state changes can still occur
00527         killPlayer();
00528 
00529         /* ensure that key events don't mess up our previewVideoStates */
00530         previewVideoState = (previewVideoState == kKilled) ?
00531             kKilled :  kKilling;
00532 
00533         /* NOTE: need unlock/process/lock here because we need
00534            to allow drawVideo() to run to handle changes in
00535            previewVideoStates */
00536         qApp->unlock();
00537         qApp->processEvents();
00538         usleep(500);
00539         qApp->lock();
00540     }
00541     previewVideoState = kStopped;
00542 
00543     ignoreKeyPressEvents = false;
00544 }
00545 
00546 void PlaybackBox::LoadWindow(QDomElement &element)
00547 {
00548     for (QDomNode child = element.firstChild(); !child.isNull();
00549          child = child.nextSibling())
00550     {
00551         QDomElement e = child.toElement();
00552         if (!e.isNull())
00553         {
00554             if (e.tagName() == "font")
00555             {
00556                 theme->parseFont(e);
00557             }
00558             else if (e.tagName() == "container")
00559             {
00560                 parseContainer(e);
00561             }
00562             else if (e.tagName() == "popup")
00563             {
00564                 parsePopup(e);
00565             }
00566             else
00567             {
00568                 VERBOSE(VB_IMPORTANT,
00569                         QString("PlaybackBox::LoadWindow(): Ignoring unknown "
00570                                 "element, %1. ").arg(e.tagName()));
00571             }
00572         }
00573     }
00574 }
00575 
00576 void PlaybackBox::parseContainer(QDomElement &element)
00577 {
00578     QRect area;
00579     QString name;
00580     int context;
00581     theme->parseContainer(element, name, context, area);
00582 
00583     if (name.lower() == "selector")
00584         drawListBounds = area;
00585     if (name.lower() == "program_info_play" && context == 0 && type != Delete)
00586         drawInfoBounds = area;
00587     if (name.lower() == "program_info_del" && context == 1 && type == Delete)
00588         drawInfoBounds = area;
00589     if (name.lower() == "video")
00590     {
00591         drawVideoBounds = area;
00592         blackholeBounds = area;
00593     }
00594     if (name.lower() == "group_info")
00595         drawGroupBounds = area;
00596     if (name.lower() == "usage")
00597         drawUsageBounds = area;
00598     if (name.lower() == "cur_group")
00599         drawCurGroupBounds = area;
00600 
00601 }
00602 
00603 void PlaybackBox::parsePopup(QDomElement &element)
00604 {
00605     QString name = element.attribute("name", "");
00606     if (name.isNull() || name.isEmpty() || name != "confirmdelete")
00607     {
00608         if (name.isNull())
00609             name = "(null)";
00610         VERBOSE(VB_IMPORTANT,
00611                 QString("PlaybackBox::parsePopup(): Popup name must "
00612                         "be 'confirmdelete' but was '%1'").arg(name));
00613         return;
00614     }
00615 
00616     for (QDomNode child = element.firstChild(); !child.isNull();
00617          child = child.nextSibling())
00618     {
00619         QDomElement info = child.toElement();
00620         if (!info.isNull())
00621         {
00622             if (info.tagName() == "solidbgcolor")
00623             {
00624                 QString col = theme->getFirstText(info);
00625                 drawPopupBgColor = QColor(col);
00626                 drawPopupSolid = false;
00627             }
00628             else if (info.tagName() == "foreground")
00629             {
00630                 QString col = theme->getFirstText(info);
00631                 drawPopupFgColor = QColor(col);
00632             }
00633             else if (info.tagName() == "highlight")
00634             {
00635                 QString col = theme->getFirstText(info);
00636                 drawPopupSelColor = QColor(col);
00637             }
00638             else
00639             {
00640                 VERBOSE(VB_IMPORTANT,
00641                         QString("PlaybackBox::parsePopup(): Unknown child %1")
00642                         .arg(info.tagName()));
00643             }
00644         }
00645     }
00646 }
00647 
00648 void PlaybackBox::exitWin()
00649 {
00650     if (m_player)
00651     {
00652         if (curitem)
00653             delete curitem;
00654         curitem = NULL;
00655         pbbIsVisibleCond.wakeAll();
00656     }
00657     else
00658         killPlayerSafe();
00659 
00660     accept();
00661 }
00662 
00663 void PlaybackBox::updateBackground(void)
00664 {
00665     QPixmap bground(size());
00666     bground.fill(this, 0, 0);
00667 
00668     QPainter tmp(&bground);
00669 
00670     LayerSet *container = theme->GetSet("background");
00671     if (container && type != Delete)
00672         container->Draw(&tmp, 0, 0);
00673     else
00674         container->Draw(&tmp, 0, 1);
00675 
00676     tmp.end();
00677     paintBackgroundPixmap = bground;
00678 
00679     setPaletteBackgroundPixmap(paintBackgroundPixmap);
00680 }
00681 
00682 void PlaybackBox::paintEvent(QPaintEvent *e)
00683 {
00684     if (e->erased())
00685         paintSkipUpdate = false;
00686 
00687     QRect r = e->rect();
00688     QPainter p(this);
00689 
00690     if (r.intersects(drawListBounds) && !paintSkipUpdate)
00691     {
00692         updateShowTitles(&p);
00693     }
00694 
00695     if (r.intersects(drawInfoBounds) && !paintSkipUpdate)
00696     {
00697         updateInfo(&p);
00698     }
00699 
00700     if (r.intersects(drawCurGroupBounds) && !paintSkipUpdate)
00701     {
00702         updateCurGroup(&p);
00703     }
00704 
00705     if (r.intersects(drawUsageBounds) && !paintSkipUpdate)
00706     {
00707         updateUsage(&p);
00708     }
00709 
00710     if (r.intersects(drawVideoBounds) && !paintSkipUpdate)
00711     {
00712         updateVideo(&p);
00713     }
00714 
00715     if (r.intersects(blackholeBounds))
00716     {
00717         drawVideo(&p);
00718     }
00719 
00720     paintSkipCount--;
00721     if (paintSkipCount < 0)
00722     {
00723         paintSkipUpdate = true;
00724         paintSkipCount = 0;
00725     }
00726 }
00727 
00728 void PlaybackBox::grayOut(QPainter *tmp)
00729 {
00730     (void)tmp;
00731 /*
00732     int transparentFlag = gContext->GetNumSetting("PlayBoxShading", 0);
00733     if (transparentFlag == 0)
00734         tmp->fillRect(QRect(QPoint(0, 0), size()),
00735                       QBrush(QColor(10, 10, 10), Dense4Pattern));
00736     else if (transparentFlag == 1)
00737     {
00738         int ww, hh;
00739 
00740         if (d->IsWideMode())
00741         {
00742             ww = 1280;
00743             hh = 720;
00744         }
00745         else
00746         {
00747             ww = 800;
00748             hh = 600;
00749         }
00750         tmp->drawPixmap(0, 0, *drawTransPixmap, 0, 0, (int)(ww*wmult),
00751                         (int)(hh*hmult));
00752     }
00753 */
00754 }
00755 void PlaybackBox::updateCurGroup(QPainter *p)
00756 {
00757     QRect pr = drawCurGroupBounds;
00758     QPixmap pix(pr.size());
00759     pix.fill(this, pr.topLeft());
00760     if (recGroup != "Default")
00761         updateGroupInfo(p, pr, pix, "cur_group");
00762     else
00763     {
00764         LayerSet *container = theme->GetSet("cur_group");
00765         if (container)
00766         {
00767             QPainter tmp(&pix);
00768 
00769             container->ClearAllText();
00770             container->Draw(&tmp, 6, 1);
00771 
00772             tmp.end();
00773             p->drawPixmap(pr.topLeft(), pix);
00774         }
00775 
00776     }
00777 }
00778 
00779 
00780 void PlaybackBox::updateGroupInfo(QPainter *p, QRect& pr,
00781                                   QPixmap& pix, QString cont_name)
00782 {
00783     LayerSet *container = theme->GetSet(cont_name);
00784     if ( container)
00785     {
00786         container->ClearAllText();
00787         QPainter tmp(&pix);
00788         QMap<QString, QString> infoMap;
00789         int countInGroup; // = progLists[""].count();
00790 
00791         if (titleList[titleIndex] == "")
00792         {
00793            countInGroup = progLists[""].count();
00794            infoMap["title"] = groupDisplayName;
00795            infoMap["group"] = groupDisplayName;
00796            infoMap["show"] = QObject::tr("All Programs");
00797         }
00798         else
00799         {
00800             countInGroup = progLists[titleList[titleIndex].lower()].count();
00801             infoMap["group"] = groupDisplayName;
00802             infoMap["show"] = titleList[titleIndex];
00803             infoMap["title"] = QString("%1 - %2").arg(groupDisplayName)
00804                                                  .arg(titleList[titleIndex]);
00805         }
00806 
00807         if (countInGroup > 1)
00808             infoMap["description"] = QString(tr("There are %1 recordings in "
00809                                                 "this display group"))
00810                                                 .arg(countInGroup);
00811         else if (countInGroup == 1)
00812             infoMap["description"] = QString(tr("There is one recording in "
00813                                                  "this display group"));
00814         else
00815             infoMap["description"] = QString(tr("There are no recordings in "
00816                                                 "this display group"));
00817 
00818         infoMap["rec_count"] = QString("%1").arg(countInGroup);
00819 
00820         container->SetText(infoMap);
00821 
00822         if (type != Delete)
00823             container->Draw(&tmp, 6, 0);
00824         else
00825             container->Draw(&tmp, 6, 1);
00826 
00827         tmp.end();
00828         p->drawPixmap(pr.topLeft(), pix);
00829     }
00830     else
00831     {
00832         if (cont_name == "group_info")
00833             updateProgramInfo(p, pr, pix);
00834     }
00835 }
00836 
00837 
00838 void PlaybackBox::updateProgramInfo(QPainter *p, QRect& pr, QPixmap& pix)
00839 {
00840     QMap<QString, QString> infoMap;
00841     QPainter tmp(&pix);
00842 
00843     if (previewVideoPlaying)
00844         previewVideoState = kChanging;
00845 
00846     LayerSet *container = NULL;
00847     if (type != Delete)
00848         container = theme->GetSet("program_info_play");
00849     else
00850         container = theme->GetSet("program_info_del");
00851 
00852     if (container)
00853     {
00854         if (curitem)
00855             curitem->ToMap(infoMap);
00856 
00857         if ((previewVideoEnabled == 0) &&
00858             (previewPixmapEnabled == 0))
00859             container->UseAlternateArea(true);
00860 
00861         container->ClearAllText();
00862         container->SetText(infoMap);
00863 
00864         int flags = 0;
00865         if (curitem)
00866             flags = curitem->programflags;
00867 
00868         QMap <QString, int>::iterator it;
00869         QMap <QString, int> iconMap;
00870 
00871         iconMap["commflagged"] = FL_COMMFLAG;
00872         iconMap["cutlist"]     = FL_CUTLIST;
00873         iconMap["autoexpire"]  = FL_AUTOEXP;
00874         iconMap["processing"]  = FL_EDITING;
00875         iconMap["bookmark"]    = FL_BOOKMARK;
00876         iconMap["inuse"]       = (FL_INUSERECORDING | FL_INUSEPLAYING);
00877         iconMap["transcoded"]  = FL_TRANSCODED;
00878         iconMap["watched"]     = FL_WATCHED;
00879         iconMap["preserved"]   = FL_PRESERVED;
00880 
00881         UIImageType *itype;
00882         for (it = iconMap.begin(); it != iconMap.end(); ++it)
00883         {
00884             itype = (UIImageType *)container->GetType(it.key());
00885             if (itype)
00886             {
00887                 if (flags & it.data())
00888                     itype->show();
00889                 else
00890                     itype->hide();
00891             }
00892         }
00893 
00894         iconMap.clear();
00895 
00896         if (curitem)
00897         {
00898 
00899             iconMap["dolby"]  = AUD_DOLBY;
00900             iconMap["surround"]  = AUD_SURROUND;
00901             iconMap["stereo"] = AUD_STEREO;
00902             iconMap["mono"] = AUD_MONO;
00903 
00904             bool haveaudicon = false;
00905 
00906             for (it = iconMap.begin(); it != iconMap.end(); ++it)
00907             {
00908                 itype = (UIImageType *)container->GetType(it.key());
00909                 if (itype)
00910                 {
00911                     itype->hide();
00912 
00913                     if (!haveaudicon && (curitem->audioproperties & it.data()))
00914                     {
00915                         itype->show();
00916                         // We only want one icon displayed
00917                         haveaudicon = true;
00918                     }
00919                 }
00920             }
00921 
00922             iconMap.clear();
00923 
00924             iconMap["hdtv"] = VID_HDTV;
00925             iconMap["widescreen"] = VID_WIDESCREEN;
00926 
00927             bool havevidicon = false;
00928 
00929             for (it = iconMap.begin(); it != iconMap.end(); ++it)
00930             {
00931                 itype = (UIImageType *)container->GetType(it.key());
00932                 if (itype)
00933                 {
00934                     itype->hide();
00935 
00936                     if (!havevidicon && (curitem->videoproperties & it.data()))
00937                     {
00938                         itype->show();
00939                         // We only want one icon displayed
00940                         havevidicon = true;
00941                     }
00942                 }
00943             }
00944 
00945             iconMap.clear();
00946 
00947             iconMap["onscreensub"] = SUB_ONSCREEN;
00948             iconMap["subtitles"] = SUB_NORMAL;
00949             iconMap["cc"] = SUB_HARDHEAR;
00950             iconMap["deafsigned"] = SUB_SIGNED;
00951 
00952             bool havesubicon = false;
00953 
00954             for (it = iconMap.begin(); it != iconMap.end(); ++it)
00955             {
00956                 itype = (UIImageType *)container->GetType(it.key());
00957                 if (itype)
00958                 {
00959                     itype->hide();
00960                     if (!havesubicon && (curitem->subtitleType & it.data()))
00961                     {
00962                         itype->show();
00963                         // We only want one icon displayed
00964                         havesubicon = true;
00965                     }
00966                 }
00967             }
00968 
00969         }
00970 
00971         container->Draw(&tmp, 6, (type == Delete) ? 1 : 0);
00972     }
00973 
00974     tmp.end();
00975     p->drawPixmap(pr.topLeft(), pix);
00976 
00977     previewVideoStartTimer.start();
00978     previewVideoStartTimerOn = true;
00979 }
00980 
00981 void PlaybackBox::updateInfo(QPainter *p)
00982 {
00983     QRect pr = drawInfoBounds;
00984     bool updateGroup = (inTitle && haveGroupInfoSet);
00985     if (updateGroup)
00986         pr = drawGroupBounds;
00987 
00988     QPixmap pix(pr.size());
00989 
00990     pix.fill(this, pr.topLeft());
00991 
00992     if (titleList.count() > 1 && curitem && !updateGroup)
00993         updateProgramInfo(p, pr, pix);
00994     else if (updateGroup)
00995         updateGroupInfo(p, pr, pix);
00996     else
00997     {
00998         QPainter tmp(&pix);
00999         LayerSet *norec = theme->GetSet("norecordings_info");
01000         if (type != Delete && norec)
01001             norec->Draw(&tmp, 8, 0);
01002         else if (norec)
01003             norec->Draw(&tmp, 8, 1);
01004 
01005         tmp.end();
01006         p->drawPixmap(pr.topLeft(), pix);
01007     }
01008 }
01009 
01010 void PlaybackBox::updateVideo(QPainter *p)
01011 {
01012     if ((! previewVideoEnabled && ! previewPixmapEnabled) ||
01013             inTitle && haveGroupInfoSet)
01014     {
01015         return;
01016     }
01017 
01018     LayerSet *container = NULL;
01019     container = theme->GetSet("video");
01020     UIBlackHoleType *blackhole = NULL;
01021     blackhole = (UIBlackHoleType *)container->GetType("video_blackhole");
01022     if (blackhole)
01023     {
01024         blackholeBounds = blackhole->getScreenArea();
01025         QPixmap pix(drawVideoBounds.size());
01026         pix.fill(this, drawVideoBounds.topLeft());
01027         QPainter tmp(&pix);
01028         container->Draw(&tmp, 1, 1);
01029         tmp.end();
01030         p->drawPixmap(drawVideoBounds.topLeft(), pix);
01031     }
01032 }
01033 
01034 void PlaybackBox::drawVideo(QPainter *p)
01035 {
01036 
01037     if (playbackVideoContainer)
01038     {
01039         m_player->DrawUnusedRects(false);
01040         return;
01041     }
01042     // If we're displaying group info don't update the video.
01043     if (inTitle && haveGroupInfoSet)
01044         return;
01045 
01046     /* show a still frame if the user doesn't want a video preview or nvp
01047      * hasn't started playing the video preview yet */
01048     if (curitem && !playingSomething &&
01049         (!previewVideoEnabled             ||
01050          !previewVideoPlaying             ||
01051          (previewVideoState == kStarting) ||
01052          (previewVideoState == kChanging)))
01053     {
01054         QPixmap temp = getPixmap(curitem);
01055         if (temp.width() > 0)
01056         {
01057             int pixmap_y = 0;
01058             int pixmap_x = 0;
01059 
01060             // Centre preview in the y axis
01061             if (temp.height() < blackholeBounds.height())
01062                 pixmap_y = blackholeBounds.y() +
01063                                 (blackholeBounds.height() - temp.height()) / 2;
01064             else
01065                 pixmap_y = blackholeBounds.y();
01066 
01067             // Centre preview in the x axis
01068             if (temp.width() < blackholeBounds.width())
01069                 pixmap_x = blackholeBounds.x() +
01070                                 (blackholeBounds.width() - temp.width()) / 2;
01071             else
01072                 pixmap_x = blackholeBounds.x();
01073 
01074             p->drawPixmap(pixmap_x, pixmap_y, temp);
01075         }
01076     }
01077 
01078     /* keep calling killPlayer() to handle nvp cleanup */
01079     /* until killPlayer() is done */
01080     if (previewVideoKillState != kDone && !killPlayer())
01081         return;
01082 
01083     /* if we aren't supposed to have a preview playing then always go */
01084     /* to the stopping previewVideoState */
01085     if (!previewVideoEnabled &&
01086         (previewVideoState != kKilling) && (previewVideoState != kKilled))
01087     {
01088         previewVideoState = kStopping;
01089     }
01090 
01091     /* if we have no nvp and aren't playing yet */
01092     /* if we have an item we should start playing */
01093     if (!previewVideoNVP   && previewVideoEnabled  &&
01094         curitem            && !previewVideoPlaying &&
01095         (previewVideoState != kKilling) &&
01096         (previewVideoState != kKilled)  &&
01097         (previewVideoState != kStarting))
01098     {
01099         ProgramInfo *rec = curitem;
01100 
01101         if (fileExists(rec) == false)
01102         {
01103             VERBOSE(VB_IMPORTANT, QString("Error: File '%1' missing.")
01104                     .arg(rec->pathname));
01105 
01106             previewVideoState = kStopping;
01107 
01108             ProgramInfo *tmpItem = findMatchingProg(rec);
01109             if (tmpItem)
01110                 tmpItem->availableStatus = asFileNotFound;
01111 
01112             return;
01113         }
01114         previewVideoState = kStarting;
01115     }
01116 
01117     if (previewVideoState == kChanging)
01118     {
01119         if (previewVideoNVP)
01120         {
01121             killPlayer(); /* start killing the player */
01122             return;
01123         }
01124 
01125         previewVideoState = kStarting;
01126     }
01127 
01128     if ((previewVideoState == kStarting) &&
01129         (!previewVideoStartTimerOn ||
01130          (previewVideoStartTimer.elapsed() > 500)))
01131     {
01132         previewVideoStartTimerOn = false;
01133 
01134         if (!previewVideoNVP)
01135             startPlayer(curitem);
01136 
01137         if (previewVideoNVP)
01138         {
01139             if (previewVideoNVP->IsPlaying())
01140             {
01141                 previewVideoState = kPlaying;
01142             }
01143         }
01144         else
01145         {
01146             // already dead, so clean up
01147             killPlayer();
01148             return;
01149         }
01150     }
01151 
01152     if ((previewVideoState == kStopping) || (previewVideoState == kKilling))
01153     {
01154         if (previewVideoNVP)
01155         {
01156             killPlayer(); /* start killing the player and exit */
01157             return;
01158         }
01159 
01160         if (previewVideoState == kKilling)
01161             previewVideoState = kKilled;
01162         else
01163             previewVideoState = kStopped;
01164     }
01165 
01166     /* if we are playing and nvp is running, then grab a new video frame */
01167     if ((previewVideoState == kPlaying) && previewVideoNVP->IsPlaying() &&
01168         !playingSomething)
01169     {
01170         QSize size = blackholeBounds.size();
01171 
01172         float saspect = (float)size.width() / (float)size.height();
01173         float vaspect = previewVideoNVP->GetVideoAspect();
01174 
01175         // Calculate new height or width according to relative aspect ratio
01176         if ((int)((saspect + 0.05) * 10) > (int)((vaspect + 0.05) * 10))
01177         {
01178             size.setWidth((int) ceil(size.width() * (vaspect / saspect)));
01179         }
01180         else if ((int)((saspect + 0.05) * 10) < (int)((vaspect + 0.05) * 10))
01181         {
01182             size.setHeight((int) ceil(size.height() * (saspect / vaspect)));
01183         }
01184 
01185         size.setHeight(((size.height() + 7) / 8) * 8);
01186         size.setWidth( ((size.width()  + 7) / 8) * 8);
01187         const QImage &img = previewVideoNVP->GetARGBFrame(size);
01188 
01189         int video_y = 0;
01190         int video_x = 0;
01191 
01192         // Centre video in the y axis
01193         if (img.height() < blackholeBounds.height())
01194             video_y = blackholeBounds.y() +
01195                             (blackholeBounds.height() - img.height()) / 2;
01196         else
01197             video_y = blackholeBounds.y();
01198 
01199         // Centre video in the x axis
01200         if (img.width() < blackholeBounds.width())
01201             video_x = blackholeBounds.x() +
01202                             (blackholeBounds.width() - img.width()) / 2;
01203         else
01204             video_x = blackholeBounds.x();
01205 
01206         p->drawImage(video_x, video_y, img);
01207     }
01208 
01209     /* have we timed out waiting for nvp to start? */
01210     if ((previewVideoState == kPlaying) && !previewVideoNVP->IsPlaying())
01211     {
01212         if (previewVideoPlayingTimer.elapsed() > 2000)
01213         {
01214             previewVideoState = kStarting;
01215             killPlayer();
01216             return;
01217         }
01218     }
01219 }
01220 
01221 void PlaybackBox::updateUsage(QPainter *p)
01222 {
01223     LayerSet *container = NULL;
01224     container = theme->GetSet("usage");
01225     if (container)
01226     {
01227         int ccontext = container->GetContext();
01228 
01229         if (ccontext != -1)
01230         {
01231             if (ccontext == 1 && type != Delete)
01232                 return;
01233             if (ccontext == 0 && type == Delete)
01234                 return;
01235         }
01236 
01237         vector<FileSystemInfo> fsInfos;
01238         if (freeSpaceNeedsUpdate && connected)
01239         {
01240             freeSpaceNeedsUpdate = false;
01241             freeSpaceTotal = 0;
01242             freeSpaceUsed = 0;
01243 
01244             fsInfos = RemoteGetFreeSpace();
01245             for (unsigned int i = 0; i < fsInfos.size(); i++)
01246             {
01247                 if (fsInfos[i].directory == "TotalDiskSpace")
01248                 {
01249                     freeSpaceTotal = (int) (fsInfos[i].totalSpaceKB >> 10);
01250                     freeSpaceUsed = (int) (fsInfos[i].usedSpaceKB >> 10);
01251                 }
01252             }
01253             freeSpaceTimer->start(15000);
01254         }
01255 
01256         QString usestr;
01257 
01258         double perc = 0.0;
01259         if (freeSpaceTotal > 0)
01260             perc = (100.0 * freeSpaceUsed) / (double) freeSpaceTotal;
01261 
01262         usestr.sprintf("%d", (int)perc);
01263         usestr = usestr + tr("% used");
01264 
01265         QString size;
01266         size.sprintf("%0.2f", (freeSpaceTotal - freeSpaceUsed) / 1024.0);
01267         QString rep = tr(", %1 GB free").arg(size);
01268         usestr = usestr + rep;
01269 
01270         QRect pr = drawUsageBounds;
01271         QPixmap pix(pr.size());
01272         pix.fill(this, pr.topLeft());
01273         QPainter tmp(&pix);
01274 
01275         UITextType *ttype = (UITextType *)container->GetType("freereport");
01276         if (ttype)
01277             ttype->SetText(usestr);
01278 
01279         UIStatusBarType *sbtype =
01280                                (UIStatusBarType *)container->GetType("usedbar");
01281         if (sbtype)
01282         {
01283             sbtype->SetUsed(freeSpaceUsed);
01284             sbtype->SetTotal(freeSpaceTotal);
01285         }
01286 
01287         if (type != Delete)
01288         {
01289             container->Draw(&tmp, 5, 0);
01290             container->Draw(&tmp, 6, 0);
01291         }
01292         else
01293         {
01294             container->Draw(&tmp, 5, 1);
01295             container->Draw(&tmp, 6, 1);
01296         }
01297 
01298         tmp.end();
01299         p->drawPixmap(pr.topLeft(), pix);
01300     }
01301 }
01302 
01303 void PlaybackBox::updateShowTitles(QPainter *p)
01304 {
01305     QString tempTitle;
01306     QString tempSubTitle;
01307     QString tempDate;
01308     QString tempTime;
01309     QString tempSize;
01310 
01311     QString match;
01312     QRect pr = drawListBounds;
01313     QPixmap pix(pr.size());
01314 
01315     LayerSet *container = NULL;
01316     pix.fill(this, pr.topLeft());
01317     QPainter tmp(&pix);
01318 
01319     LCD *lcddev = LCD::Get();
01320     QString tstring, lcdTitle;
01321     QPtrList<LCDMenuItem> lcdItems;
01322     lcdItems.setAutoDelete(true);
01323 
01324     container = theme->GetSet("selector");
01325 
01326     ProgramInfo *tempInfo;
01327 
01328     ProgramList *plist;
01329     if (titleList.count() > 1)
01330         plist = &progLists[titleList[titleIndex].lower()];
01331     else
01332         plist = &progLists[""];
01333 
01334     int progCount = plist->count();
01335 
01336     if (curitem)
01337     {
01338         delete curitem;
01339         curitem = NULL;
01340     }
01341 
01342     if (container && titleList.count() >= 1)
01343     {
01344         UIListType *ltype = (UIListType *)container->GetType("toptitles");
01345         if (ltype && titleList.count() > 1)
01346         {
01347             ltype->ResetList();
01348             ltype->SetActive(inTitle);
01349 
01350             int h = titleIndex - ltype->GetItems() +
01351                 ltype->GetItems() * titleList.count();
01352             h = h % titleList.count();
01353 
01354             for (int cnt = 0; cnt < ltype->GetItems(); cnt++)
01355             {
01356                 if (titleList[h] == "")
01357                     tstring = groupDisplayName;
01358                 else
01359                     tstring = titleList[h];
01360 
01361                 tstring.remove(QRegExp("^ "));
01362                 ltype->SetItemText(cnt, tstring);
01363                 if (lcddev && inTitle)
01364                     lcdItems.append(new LCDMenuItem(0, NOTCHECKABLE, tstring));
01365 
01366                 h++;
01367                 h = h % titleList.count();
01368              }
01369         }
01370         else if (ltype)
01371         {
01372             ltype->ResetList();
01373         }
01374 
01375         UITextType *typeText = (UITextType *)container->GetType("current");
01376         if (typeText && titleList.count() > 1)
01377         {
01378             if (titleList[titleIndex] == "")
01379                 tstring = groupDisplayName;
01380             else
01381                 tstring = titleList[titleIndex];
01382 
01383             tstring.remove(QRegExp("^ "));
01384             typeText->SetText(tstring);
01385             if (lcddev)
01386             {
01387                 if (inTitle)
01388                 {
01389                     lcdItems.append(new LCDMenuItem(1, NOTCHECKABLE, tstring));
01390                     lcdTitle = "Recordings";
01391                 }
01392                 else
01393                     lcdTitle = " <<" + tstring;
01394             }
01395         }
01396         else if (typeText)
01397         {
01398             typeText->SetText("");
01399         }
01400 
01401         ltype = (UIListType *)container->GetType("bottomtitles");
01402         if (ltype && titleList.count() > 1)
01403         {
01404             ltype->ResetList();
01405             ltype->SetActive(inTitle);
01406 
01407             int h = titleIndex + 1;
01408             h = h % titleList.count();
01409 
01410             for (int cnt = 0; cnt < ltype->GetItems(); cnt++)
01411             {
01412                 if (titleList[h] == "")
01413                     tstring = groupDisplayName;
01414                 else
01415                     tstring = titleList[h];
01416 
01417                 tstring.remove(QRegExp("^ "));
01418                 ltype->SetItemText(cnt, tstring);
01419                 if (lcddev && inTitle)
01420                     lcdItems.append(new LCDMenuItem(0, NOTCHECKABLE, tstring));
01421 
01422                 h++;
01423                 h = h % titleList.count();
01424             }
01425         }
01426         else if (ltype)
01427         {
01428             ltype->ResetList();
01429         }
01430 
01431         ltype = (UIListType *)container->GetType("showing");
01432         if (ltype && titleList.count() > 1)
01433         {
01434             ltype->ResetList();
01435             ltype->SetActive(!inTitle);
01436 
01437             int skip;
01438             if (progCount <= listsize || progIndex <= listsize / 2)
01439                 skip = 0;
01440             else if (progIndex >= progCount - listsize + listsize / 2)
01441                 skip = progCount - listsize;
01442             else
01443                 skip = progIndex - listsize / 2;
01444 
01445             ltype->SetUpArrow(skip > 0);
01446             ltype->SetDownArrow(skip + listsize < progCount);
01447 
01448             int cnt;
01449             for (cnt = 0; cnt < listsize; cnt++)
01450             {
01451                 if (cnt + skip >= progCount)
01452                     break;
01453 
01454                 tempInfo = plist->at(skip+cnt);
01455 
01456                 if (titleList[titleIndex] != tempInfo->title)
01457                 {
01458                     tempSubTitle = tempInfo->title;
01459                     if (tempInfo->subtitle.stripWhiteSpace().length() > 0)
01460                         tempSubTitle = tempSubTitle + " - \"" +
01461                                        tempInfo->subtitle + "\"";
01462                 }
01463                 else
01464                 {
01465                     tempSubTitle = tempInfo->subtitle;
01466                     if (tempSubTitle.stripWhiteSpace().length() == 0)
01467                         tempSubTitle = tempInfo->title;
01468                 }
01469 
01470                 tempDate = (tempInfo->recstartts).toString(formatShortDate);
01471                 tempTime = (tempInfo->recstartts).toString(formatTime);
01472 
01473                 long long size = tempInfo->filesize;
01474                 tempSize.sprintf("%0.2f GB", size / 1024.0 / 1024.0 / 1024.0);
01475 
01476                 if (skip + cnt == progIndex)
01477                 {
01478                     curitem = new ProgramInfo(*tempInfo);
01479                     ltype->SetItemCurrent(cnt);
01480                 }
01481 
01482                 if (lcddev && !inTitle)
01483                 {
01484                     QString lcdSubTitle = tempSubTitle;
01485                     lcdItems.append(new LCDMenuItem(skip + cnt == progIndex,
01486                                     NOTCHECKABLE,
01487                                     lcdSubTitle.replace('"', "'") +
01488                                     " " + tempDate));
01489                 }
01490 
01491                 ltype->SetItemText(cnt, 1, tempSubTitle);
01492                 ltype->SetItemText(cnt, 2, tempDate);
01493                 ltype->SetItemText(cnt, 3, tempTime);
01494                 ltype->SetItemText(cnt, 4, tempSize);
01495                 if (tempInfo->recstatus == rsRecording)
01496                     ltype->EnableForcedFont(cnt, "recording");
01497 
01498                 if (playList.grep(tempInfo->MakeUniqueKey()).count())
01499                     ltype->EnableForcedFont(cnt, "tagged");
01500 
01501                 if (((tempInfo->recstatus != rsRecording) &&
01502                      (tempInfo->availableStatus != asAvailable) &&
01503                      (tempInfo->availableStatus != asNotYetAvailable)) ||
01504                     (m_player && m_player->IsSameProgram(tempInfo)))
01505                     ltype->EnableForcedFont(cnt, "inactive");
01506             }
01507         }
01508         else if (ltype)
01509         {
01510             ltype->ResetList();
01511         }
01512     }
01513 
01514     if (lcddev && !lcdItems.isEmpty())
01515         lcddev->switchToMenu(&lcdItems, lcdTitle);
01516 
01517     // DRAW LAYERS
01518     if (container && type != Delete)
01519     {
01520         container->Draw(&tmp, 0, 0);
01521         container->Draw(&tmp, 1, 0);
01522         container->Draw(&tmp, 2, 0);
01523         container->Draw(&tmp, 3, 0);
01524         container->Draw(&tmp, 4, 0);
01525         container->Draw(&tmp, 5, 0);
01526         container->Draw(&tmp, 6, 0);
01527         container->Draw(&tmp, 7, 0);
01528         container->Draw(&tmp, 8, 0);
01529     }
01530     else
01531     {
01532         container->Draw(&tmp, 0, 1);
01533         container->Draw(&tmp, 1, 1);
01534         container->Draw(&tmp, 2, 1);
01535         container->Draw(&tmp, 3, 1);
01536         container->Draw(&tmp, 4, 1);
01537         container->Draw(&tmp, 5, 1);
01538         container->Draw(&tmp, 6, 1);
01539         container->Draw(&tmp, 7, 1);
01540         container->Draw(&tmp, 8, 1);
01541     }
01542 
01543     leftRight = false;
01544 
01545     if (titleList.count() <= 1)
01546     {
01547         LayerSet *norec = theme->GetSet("norecordings_list");
01548         UITextType *ttype = (UITextType *)norec->GetType("msg");
01549         if (ttype)
01550         {
01551             progCacheLock.lock();
01552             if (progCache && !progCache->empty())
01553                 ttype->SetText(tr(
01554                     "There are no recordings in your current view"));
01555             else
01556                 ttype->SetText(tr(
01557                     "There are no recordings available"));
01558             progCacheLock.unlock();
01559         }
01560 
01561         if (type != Delete && norec)
01562             norec->Draw(&tmp, 8, 0);
01563         else if (norec)
01564             norec->Draw(&tmp, 8, 1);
01565     }
01566 
01567     tmp.end();
01568     p->drawPixmap(pr.topLeft(), pix);
01569 
01570     if (titleList.count() <= 1)
01571         update(drawInfoBounds);
01572 }
01573 
01574 void PlaybackBox::cursorLeft()
01575 {
01576     if (!inTitle)
01577     {
01578         if (haveGroupInfoSet)
01579             killPlayerSafe();
01580 
01581         inTitle = true;
01582         paintSkipUpdate = false;
01583 
01584         update(drawTotalBounds);
01585         leftRight = true;
01586     }
01587     else if (arrowAccel)
01588         exitWin();
01589 
01590 }
01591 
01592 void PlaybackBox::cursorRight()
01593 {
01594     if (inTitle)
01595     {
01596         leftRight = true;
01597         inTitle = false;
01598         paintSkipUpdate = false;
01599         update(drawTotalBounds);
01600     }
01601     else if (arrowAccel)
01602         showActionsSelected();
01603     else if (curitem && curitem->availableStatus != asAvailable)
01604         showAvailablePopup(curitem);
01605 }
01606 
01607 void PlaybackBox::cursorDown(bool page, bool newview)
01608 {
01609     if (inTitle == true || newview)
01610     {
01611         titleIndex += (page ? 5 : 1);
01612         titleIndex = titleIndex % (int)titleList.count();
01613 
01614         progIndex = 0;
01615 
01616         if (newview)
01617             inTitle = false;
01618 
01619         paintSkipUpdate = false;
01620         update(drawTotalBounds);
01621     }
01622     else
01623     {
01624         int progCount = progLists[titleList[titleIndex].lower()].count();
01625         if (progIndex < progCount - 1)
01626         {
01627             progIndex += (page ? listsize : 1);
01628             if (progIndex > progCount - 1)
01629                 progIndex = progCount - 1;
01630 
01631             paintSkipUpdate = false;
01632             update(drawListBounds);
01633             update(drawInfoBounds);
01634             update(blackholeBounds);
01635         }
01636     }
01637 }
01638 
01639 void PlaybackBox::cursorUp(bool page, bool newview)
01640 {
01641     if (inTitle == true || newview)
01642     {
01643         titleIndex -= (page ? 5 : 1);
01644         titleIndex += 5 * titleList.count();
01645         titleIndex = titleIndex % titleList.count();
01646 
01647         progIndex = 0;
01648 
01649         if (newview)
01650             inTitle = false;
01651 
01652         paintSkipUpdate = false;
01653         update(drawTotalBounds);
01654     }
01655     else
01656     {
01657         if (progIndex > 0)
01658         {
01659             progIndex -= (page ? listsize : 1);
01660             if (progIndex < 0)
01661                 progIndex = 0;
01662 
01663             paintSkipUpdate = false;
01664             update(drawListBounds);
01665             update(drawInfoBounds);
01666             update(blackholeBounds);
01667         }
01668     }
01669 }
01670 
01671 void PlaybackBox::pageTop()
01672 {
01673     if (inTitle)
01674     {
01675         titleIndex = 0;
01676 
01677         progIndex = 0;
01678 
01679         paintSkipUpdate = false;
01680         update(drawTotalBounds);
01681     }
01682     else
01683     {
01684         progIndex = 0;
01685 
01686         paintSkipUpdate = false;
01687         update(drawListBounds);
01688         update(drawInfoBounds);
01689         update(blackholeBounds);
01690     }
01691 }
01692 
01693 void PlaybackBox::pageMiddle()
01694 {
01695     if (inTitle)
01696     {
01697         titleIndex = (int)floor(titleList.count() / 2.0);
01698 
01699         progIndex = 0;
01700 
01701         paintSkipUpdate = false;
01702         update(drawTotalBounds);
01703     }
01704     else
01705     {
01706         int progCount = progLists[titleList[titleIndex].lower()].count();
01707 
01708         if (progCount > 0)
01709         {
01710             progIndex = (int)floor(progCount / 2.0);
01711 
01712             paintSkipUpdate = false;
01713             update(drawListBounds);
01714             update(drawInfoBounds);
01715             update(blackholeBounds);
01716         }
01717     }
01718 }
01719 
01720 void PlaybackBox::pageBottom()
01721 {
01722     if (inTitle)
01723         pageTop();
01724     else
01725     {
01726         progIndex = progLists[titleList[titleIndex].lower()].count() - 1;
01727 
01728         paintSkipUpdate = false;
01729         update(drawListBounds);
01730         update(drawInfoBounds);
01731         update(blackholeBounds);
01732     }
01733 }
01734 
01735 void PlaybackBox::listChanged(void)
01736 {
01737     if (playingSomething)
01738         return;
01739 
01740     connected = FillList(fillListFromCache);
01741     paintSkipUpdate = false;
01742     update(drawTotalBounds);
01743     if (type == Delete)
01744         UpdateProgressBar();
01745 }
01746 
01747 bool PlaybackBox::FillList(bool useCachedData)
01748 {
01749     ProgramInfo *p;
01750 
01751     // Save some information so we can find our place again.
01752     QString oldtitle = titleList[titleIndex];
01753     QString oldchanid;
01754     QString oldprogramid;
01755     QDate oldoriginalAirDate;
01756     QDateTime oldstartts;
01757     int oldrecpriority = 0;
01758     int oldrecordid = 0;
01759 
01760     p = progLists[oldtitle.lower()].at(progIndex);
01761     if (p)
01762     {
01763         oldchanid = p->chanid;
01764         oldstartts = p->recstartts;
01765         oldprogramid = p->programid;
01766         oldrecordid = p->recordid;
01767         oldoriginalAirDate = p->originalAirDate;
01768         oldrecpriority = p->recpriority;
01769     }
01770 
01771     QMap<QString, AvailableStatusType> asCache;
01772     QString asKey;
01773     for (unsigned int i = 0; i < progLists[""].count(); i++)
01774     {
01775         p = progLists[""].at(i);
01776         asKey = p->MakeUniqueKey();
01777         asCache[asKey] = p->availableStatus;
01778     }
01779 
01780     progsInDB = 0;
01781     titleList.clear();
01782     progLists.clear();
01783     // Clear autoDelete for the "all" list since it will share the
01784     // objects with the title lists.
01785     progLists[""].setAutoDelete(false);
01786 
01787     fillRecGroupPasswordCache();
01788 
01789     ViewTitleSort titleSort = (ViewTitleSort)gContext->GetNumSetting(
01790             "DisplayGroupTitleSort", TitleSortAlphabetical);
01791 
01792     QMap<QString, QString> sortedList;
01793     QMap<int, QString> searchRule;
01794     QMap<int, int> recidEpisodes;
01795     QString sTitle = "";
01796 
01797     bool LiveTVInAllPrograms = gContext->GetNumSetting("LiveTVInAllPrograms",0);
01798 
01799     progCacheLock.lock();
01800     if (!useCachedData || !progCache || progCache->empty())
01801     {
01802         clearProgramCache();
01803 
01804         progCache = RemoteGetRecordedList(allOrder == 0 || type == Delete);
01805     }
01806     else
01807     {
01808         // Validate the cache
01809         vector<ProgramInfo *>::iterator i = progCache->begin();
01810         for ( ; i != progCache->end(); )
01811         {
01812             if ((*i)->availableStatus == asDeleted)
01813             {
01814                 delete *i;
01815                 i = progCache->erase(i);
01816             }
01817             else
01818                 i++;
01819         }
01820     }
01821 
01822     if (progCache)
01823     {
01824         if ((viewMask & VIEW_SEARCHES))
01825         {
01826             MSqlQuery query(MSqlQuery::InitCon());
01827             query.prepare("SELECT recordid,title FROM record "
01828                           "WHERE search > 0 AND search != :MANUAL;");
01829             query.bindValue(":MANUAL", kManualSearch);
01830 
01831             if (query.exec() && query.isActive())
01832             {
01833                 while (query.next())
01834                 {
01835                     QString tmpTitle = query.value(1).toString();
01836                     tmpTitle.remove(QRegExp(" \\(.*\\)$"));
01837                     searchRule[query.value(0).toInt()] = tmpTitle;
01838                 }
01839             }
01840         }
01841 
01842         if (!(viewMask & VIEW_WATCHLIST))
01843             watchListStart = 0;
01844 
01845         sortedList[""] = "";
01846         vector<ProgramInfo *>::iterator i = progCache->begin();
01847         for ( ; i != progCache->end(); i++)
01848         {
01849             progsInDB++;
01850             p = *i;
01851 
01852             if (p->title == "")
01853                 p->title = tr("_NO_TITLE_");
01854 
01855             if ((((p->recgroup == recGroup) ||
01856                   ((recGroup == "All Programs") &&
01857                    (p->recgroup != "Deleted") &&
01858                    (p->recgroup != "LiveTV" || LiveTVInAllPrograms))) &&
01859                  (recGroupPassword == curGroupPassword)) ||
01860                 ((recGroupType[recGroup] == "category") &&
01861                  ((p->category == recGroup ) ||
01862                   ((p->category == "") && (recGroup == tr("Unknown")))) &&
01863                  ( !recGroupPwCache.contains(p->recgroup))))
01864             {
01865                 if (viewMask != VIEW_NONE)
01866                     progLists[""].prepend(p);
01867 
01868                 asKey = p->MakeUniqueKey();
01869                 if (asCache.contains(asKey))
01870                     p->availableStatus = asCache[asKey];
01871                 else
01872                     p->availableStatus = asAvailable;
01873 
01874                 if ((viewMask & VIEW_TITLES) && // Show titles
01875                     ((p->recgroup != "LiveTV") ||
01876                      (recGroup == "LiveTV") ||
01877                      ((recGroup == "All Programs") &&
01878                       ((viewMask & VIEW_LIVETVGRP) == 0))))
01879                 {
01880                     sTitle = sortTitle(p->title, viewMask, titleSort,
01881                             p->recpriority);
01882                     sTitle = sTitle.lower();
01883 
01884                     if (!sortedList.contains(sTitle))
01885                         sortedList[sTitle] = p->title;
01886                     progLists[sortedList[sTitle].lower()].prepend(p);
01887                     progLists[sortedList[sTitle].lower()].setAutoDelete(false);
01888                 }
01889 
01890                 if ((viewMask & VIEW_RECGROUPS) &&
01891                     p->recgroup != "") // Show recording groups
01892                 {
01893                     sortedList[p->recgroup.lower()] = p->recgroup;
01894                     progLists[p->recgroup.lower()].prepend(p);
01895                     progLists[p->recgroup.lower()].setAutoDelete(false);
01896                 }
01897 
01898                 if ((viewMask & VIEW_CATEGORIES) &&
01899                     p->category != "") // Show categories
01900                 {
01901                     sortedList[p->category.lower()] = p->category;
01902                     progLists[p->category.lower()].prepend(p);
01903                     progLists[p->category.lower()].setAutoDelete(false);
01904                 }
01905 
01906                 if ((viewMask & VIEW_SEARCHES) &&
01907                     searchRule[p->recordid] != "" &&
01908                     p->title != searchRule[p->recordid]) // Show search rules
01909                 {
01910                     QString tmpTitle = QString("(%1)")
01911                                                .arg(searchRule[p->recordid]);
01912                     sortedList[tmpTitle.lower()] = tmpTitle;
01913                     progLists[tmpTitle.lower()].prepend(p);
01914                     progLists[tmpTitle.lower()].setAutoDelete(false);
01915                 }
01916 
01917                 if ((LiveTVInAllPrograms) &&
01918                     (recGroup == "All Programs") &&
01919                     (viewMask & VIEW_LIVETVGRP) &&
01920                     (p->recgroup == "LiveTV"))
01921                 {
01922                     QString tmpTitle = QString(" %1").arg(tr("LiveTV"));
01923                     sortedList[tmpTitle.lower()] = tmpTitle;
01924                     progLists[tmpTitle.lower()].prepend(p);
01925                     progLists[tmpTitle.lower()].setAutoDelete(false);
01926                 }
01927 
01928                 if ((viewMask & VIEW_WATCHLIST) && (p->recgroup != "LiveTV"))
01929                 {
01930                     if (watchListAutoExpire && !p->GetAutoExpireFromRecorded())
01931                     {
01932                         p->recpriority2 = wlExpireOff;
01933                         VERBOSE(VB_FILE, QString("Auto-expire off:  %1")
01934                                                  .arg(p->title));
01935                     }
01936                     else if (p->programflags & FL_WATCHED)
01937                     {
01938                         p->recpriority2 = wlWatched;
01939                         VERBOSE(VB_FILE, QString("Marked as 'watched':  %1")
01940                                                  .arg(p->title));
01941                     }
01942                     else
01943                     {
01944                         if (p->recordid > 0)
01945                             recidEpisodes[p->recordid] += 1;
01946                         if (recidEpisodes[p->recordid] == 1 ||
01947                             p->recordid == 0 )
01948                         {
01949                             sortedList[watchGroupLabel] = watchGroupName;
01950                             progLists[watchGroupLabel].prepend(p);
01951                             progLists[watchGroupLabel].setAutoDelete(false);
01952                         }
01953                         else
01954                         {
01955                             p->recpriority2 = wlEarlier;
01956                             VERBOSE(VB_FILE, QString("Not the earliest:  %1")
01957                                                      .arg(p->title));
01958                         }
01959                     }
01960                 }
01961             }
01962         }
01963     }
01964     progCacheLock.unlock();
01965 
01966     if (sortedList.count() == 0)
01967     {
01968         progLists[""];
01969         titleList << "";
01970         progIndex = 0;
01971         titleIndex = 0;
01972         playList.clear();
01973 
01974         return 0;
01975     }
01976 
01977     QString episodeSort = gContext->GetSetting("PlayBoxEpisodeSort", "Date");
01978 
01979     if (episodeSort == "OrigAirDate")
01980     {
01981         QMap<QString, ProgramList>::Iterator Iprog;
01982         for (Iprog = progLists.begin(); Iprog != progLists.end(); ++Iprog)
01983         {
01984             if (!Iprog.key().isEmpty())
01985             {
01986                 if (listOrder == 0 || type == Delete)
01987                     Iprog.data().Sort(comp_originalAirDate_rev);
01988                 else
01989                     Iprog.data().Sort(comp_originalAirDate);
01990             }
01991         }
01992     }
01993     else if (episodeSort == "Id")
01994     {
01995         QMap<QString, ProgramList>::Iterator Iprog;
01996         for (Iprog = progLists.begin(); Iprog != progLists.end(); ++Iprog)
01997         {
01998             if (!Iprog.key().isEmpty())
01999             {
02000                 if (listOrder == 0 || type == Delete)
02001                     Iprog.data().Sort(comp_programid_rev);
02002                 else
02003                     Iprog.data().Sort(comp_programid);
02004             }
02005         }
02006     }
02007     else if (episodeSort == "Date")
02008     {
02009         QMap<QString, ProgramList>::iterator it;
02010         for (it = progLists.begin(); it != progLists.end(); ++it)
02011         {
02012             if (!it.key().isEmpty())
02013             {
02014                 if (!listOrder || type == Delete)
02015                     (*it).Sort(comp_recordDate_rev);
02016                 else
02017                     (*it).Sort(comp_recordDate);
02018             }
02019         }
02020     }
02021 
02022     if (progLists[watchGroupLabel].count() > 1)
02023     {
02024         QDateTime now = QDateTime::currentDateTime();
02025         int baseValue = watchListMaxAge * 2 / 3;
02026 
02027         QMap<int, int> recType;
02028         QMap<int, int> maxEpisodes;
02029         QMap<int, int> avgDelay;
02030         QMap<int, int> spanHours;
02031         QMap<int, int> delHours;
02032         QMap<int, int> nextHours;
02033 
02034         MSqlQuery query(MSqlQuery::InitCon());
02035         query.prepare("SELECT recordid, type, maxepisodes, avg_delay, "
02036                       "next_record, last_record, last_delete FROM record;");
02037 
02038         if (query.exec() && query.isActive())
02039         {
02040             while (query.next())
02041             {
02042                 int recid = query.value(0).toInt();
02043                 recType[recid] = query.value(1).toInt();
02044                 maxEpisodes[recid] = query.value(2).toInt();
02045                 avgDelay[recid] = query.value(3).toInt();
02046 
02047                 QDateTime next_record = query.value(4).toDateTime();
02048                 QDateTime last_record = query.value(5).toDateTime();
02049                 QDateTime last_delete = query.value(6).toDateTime();
02050 
02051                 // Time between the last and next recordings
02052                 spanHours[recid] = 1000;
02053                 if (last_record.isValid() && next_record.isValid())
02054                     spanHours[recid] =
02055                         last_record.secsTo(next_record) / 3600 + 1;
02056 
02057                 // Time since the last episode was deleted
02058                 delHours[recid] = 1000;
02059                 if (last_delete.isValid())
02060                     delHours[recid] = last_delete.secsTo(now) / 3600 + 1;
02061 
02062                 // Time until the next recording if any
02063                 if (next_record.isValid())
02064                     nextHours[recid] = now.secsTo(next_record) / 3600 + 1;
02065             }
02066         }
02067 
02068         ProgramInfo *p;
02069         p = progLists[watchGroupLabel].first();
02070         while (p)
02071         {
02072             int recid = p->recordid;
02073             int avgd =  avgDelay[recid];
02074 
02075             if (avgd == 0)
02076                 avgd = 100;
02077 
02078             // Set the intervals beyond range if there is no record entry
02079             if (spanHours[recid] == 0)
02080             {
02081                 spanHours[recid] = 1000;
02082                 delHours[recid] = 1000;
02083             }
02084 
02085             // add point equal to baseValue for each additional episode
02086             if (p->recordid == 0 || maxEpisodes[recid] > 0)
02087                 p->recpriority2 = 0;
02088             else
02089                 p->recpriority2 = (recidEpisodes[p->recordid] - 1) * baseValue;
02090 
02091             // add points every 3hr leading up to the next recording
02092             if (nextHours[recid] > 0 && nextHours[recid] < baseValue * 3)
02093                 p->recpriority2 += (baseValue * 3 - nextHours[recid]) / 3;
02094 
02095             int hrs = p->endts.secsTo(now) / 3600;
02096             if (hrs < 1)
02097                 hrs = 1;
02098 
02099             // add points for a new recording that decrease each hour
02100             if (hrs < 42)
02101                 p->recpriority2 += 42 - hrs;
02102 
02103             // add points for how close the recorded time of day is to 'now'
02104             p->recpriority2 += abs((hrs % 24) - 12) * 2;
02105 
02106             // Daily
02107             if (spanHours[recid] < 50 ||
02108                 recType[recid] == kTimeslotRecord ||
02109                 recType[recid] == kFindDailyRecord)
02110             {
02111                 if (delHours[recid] < watchListBlackOut * 4)
02112                 {
02113                     p->recpriority2 = wlDeleted;
02114                     VERBOSE(VB_FILE, QString("Recently deleted daily:  %1")
02115                                              .arg(p->title));
02116                     progLists[watchGroupLabel].remove();
02117                     p = progLists[watchGroupLabel].current();
02118                     continue;
02119                 }
02120                 else
02121                 {
02122                     VERBOSE(VB_FILE, QString("Daily interval:  %1")
02123                                              .arg(p->title));
02124 
02125                     if (maxEpisodes[recid] > 0)
02126                         p->recpriority2 += (baseValue / 2) + (hrs / 24);
02127                     else
02128                         p->recpriority2 += (baseValue / 5) + hrs;
02129                 }
02130             }
02131             // Weekly
02132             else if (nextHours[recid] ||
02133                      recType[recid] == kWeekslotRecord ||
02134                      recType[recid] == kFindWeeklyRecord)
02135 
02136             {
02137                 if (delHours[recid] < (watchListBlackOut * 24) - 4)
02138                 {
02139                     p->recpriority2 = wlDeleted;
02140                     VERBOSE(VB_FILE, QString("Recently deleted weekly:  %1")
02141                                              .arg(p->title));
02142                     progLists[watchGroupLabel].remove();
02143                     p = progLists[watchGroupLabel].current();
02144                     continue;
02145                 }
02146                 else
02147                 {
02148                     VERBOSE(VB_FILE, QString("Weekly interval: %1")
02149                                              .arg(p->title));
02150 
02151                     if (maxEpisodes[recid] > 0)
02152                         p->recpriority2 += (baseValue / 2) + (hrs / 24);
02153                     else
02154                         p->recpriority2 +=
02155                             (baseValue / 3) + (baseValue * hrs / 24 / 4);
02156                 }
02157             }
02158             // Not recurring
02159             else
02160             {
02161                 if (delHours[recid] < (watchListBlackOut * 48) - 4)
02162                 {
02163                     p->recpriority2 = wlDeleted;
02164                     progLists[watchGroupLabel].remove();
02165                     p = progLists[watchGroupLabel].current();
02166                     continue;
02167                 }
02168                 else
02169                 {
02170                     // add points for a new Single or final episode
02171                     if (hrs < 36)
02172                         p->recpriority2 += baseValue * (36 - hrs) / 36;
02173 
02174                     if (avgd != 100)
02175                     {
02176                         if (maxEpisodes[recid] > 0)
02177                             p->recpriority2 += (baseValue / 2) + (hrs / 24);
02178                         else
02179                             p->recpriority2 +=
02180                                 (baseValue / 3) + (baseValue * hrs / 24 / 4);
02181                     }
02182                     else if ((hrs / 24) < watchListMaxAge)
02183                         p->recpriority2 += hrs / 24;
02184                     else
02185                         p->recpriority2 += watchListMaxAge;
02186                 }
02187             }
02188 
02189             // Factor based on the average time shift delay.
02190             // Scale the avgd range of 0 thru 200 hours to 133% thru 67%
02191             int delaypct = avgd / 3 + 67;
02192 
02193             if (avgd < 100)
02194                 p->recpriority2 = p->recpriority2 * (200 - delaypct) / 100;
02195             else if (avgd > 100)
02196                 p->recpriority2 = p->recpriority2 * 100 / delaypct;
02197 
02198             VERBOSE(VB_FILE, QString(" %1  %2  %3")
02199                     .arg(p->startts.toString(formatShortDate))
02200                     .arg(p->recpriority2).arg(p->title));
02201 
02202             p = progLists[watchGroupLabel].next();
02203         }
02204         progLists[watchGroupLabel].Sort(comp_recpriority2);
02205     }
02206 
02207     // Try to find our old place in the title list.  Scan the new
02208     // titles backwards until we find where we were or go past.  This
02209     // is somewhat inefficient, but it works.
02210 
02211     QStringList sTitleList = sortedList.keys();
02212     titleList = sortedList.values();
02213 
02214     QString oldsTitle = sortTitle(oldtitle, viewMask, titleSort,
02215             oldrecpriority);
02216     oldsTitle = oldsTitle.lower();
02217     titleIndex = titleList.count() - 1;
02218     for (titleIndex = titleList.count() - 1; titleIndex >= 0; titleIndex--)
02219     {
02220         if (watchListStart && sTitleList[titleIndex] == watchGroupLabel)
02221         {
02222             watchListStart = 0;
02223             break;
02224         }
02225         sTitle = sTitleList[titleIndex];
02226         sTitle = sTitle.lower();
02227 
02228         if (oldsTitle > sTitle)
02229         {
02230             if (titleIndex + 1 < (int)titleList.count())
02231                 titleIndex++;
02232             break;
02233         }
02234 
02235         if (oldsTitle == sTitle)
02236             break;
02237     }
02238 
02239     // Now do pretty much the same thing for the individual shows on
02240     // the specific program list if needed.
02241     if (oldtitle != titleList[titleIndex] || oldchanid.isNull())
02242         progIndex = 0;
02243     else
02244     {
02245         ProgramList *l = &progLists[oldtitle.lower()];
02246         progIndex = l->count() - 1;
02247 
02248         for (int i = progIndex; i >= 0; i--)
02249         {
02250             p = l->at(i);
02251 
02252             if (oldtitle != watchGroupName)
02253             {
02254                 if (titleIndex == 0)
02255                 {
02256                     if (allOrder == 0 || type == Delete)
02257                     {
02258                         if (oldstartts > p->recstartts)
02259                             break;
02260                     }
02261                     else
02262                     {
02263                         if (oldstartts < p->recstartts)
02264                             break;
02265                     }
02266                 }
02267                 else
02268                 {
02269                     if (!listOrder || type == Delete)
02270                     {
02271                         if (episodeSort == "OrigAirDate")
02272                         {
02273                             if (oldoriginalAirDate > p->originalAirDate)
02274                                 break;
02275                         }
02276                         else if (episodeSort == "Id")
02277                         {
02278                             if (oldprogramid > p->programid)
02279                                 break;
02280                         }
02281                         else
02282                         {
02283                             if (oldstartts > p->recstartts)
02284                                 break;
02285                         }
02286                     }
02287                     else
02288                     {
02289                         if (episodeSort == "OrigAirDate")
02290                         {
02291                             if (oldoriginalAirDate < p->originalAirDate)
02292                                 break;
02293                         }
02294                         else if (episodeSort == "Id")
02295                         {
02296                             if (oldprogramid < p->programid)
02297                                 break;
02298                         }
02299                         else
02300                         {
02301                             if (oldstartts < p->recstartts)
02302                                 break;
02303                         }
02304                     }
02305                 }
02306             }
02307             progIndex = i;
02308 
02309             if (oldchanid == p->chanid &&
02310                 oldstartts == p->recstartts)
02311                 break;
02312         }
02313     }
02314 
02315     return (progCache != NULL);
02316 }
02317 
02318 static void *SpawnPreviewVideoThread(void *param)
02319 {
02320     NuppelVideoPlayer *nvp = (NuppelVideoPlayer *)param;
02321     nvp->StartPlaying();
02322     return NULL;
02323 }
02324 
02325 bool PlaybackBox::killPlayer(void)
02326 {
02327     QMutexLocker locker(&previewVideoUnsafeKillLock);
02328 
02329     previewVideoPlaying = false;
02330 
02331     /* if we don't have nvp to deal with then we are done */
02332     if (!previewVideoNVP)
02333     {
02334         previewVideoKillState = kDone;
02335         return true;
02336     }
02337 
02338     if (previewVideoKillState == kDone)
02339     {
02340         previewVideoKillState = kNvpToPlay;
02341         previewVideoKillTimeout.start();
02342     }
02343 
02344     if (previewVideoKillState == kNvpToPlay)
02345     {
02346         if (previewVideoNVP->IsPlaying() ||
02347             (previewVideoKillTimeout.elapsed() > 2000))
02348         {
02349             previewVideoKillState = kNvpToStop;
02350 
02351             previewVideoRingBuf->Pause();
02352             previewVideoNVP->StopPlaying();
02353         }
02354         else /* return false status since we aren't done yet */
02355             return false;
02356     }
02357 
02358     if (previewVideoKillState == kNvpToStop)
02359     {
02360         if (!previewVideoNVP->IsPlaying() ||
02361             (previewVideoKillTimeout.elapsed() > 2000))
02362         {
02363             pthread_join(previewVideoThread, NULL);
02364             previewVideoThreadRunning = false;
02365             delete previewVideoNVP;
02366             delete previewVideoRingBuf;
02367 
02368             previewVideoNVP = NULL;
02369             previewVideoRingBuf = NULL;
02370             previewVideoKillState = kDone;
02371         }
02372         else /* return false status since we aren't done yet */
02373             return false;
02374     }
02375 
02376     return true;
02377 }
02378 
02379 void PlaybackBox::startPlayer(ProgramInfo *rec)
02380 {
02381     previewVideoPlaying = true;
02382 
02383     if (rec != NULL)
02384     {
02385         // Don't keep trying to open broken files when just sitting on entry
02386         if (previewVideoBrokenRecId &&
02387             previewVideoBrokenRecId == rec->recordid)
02388         {
02389             return;
02390         }
02391 
02392         if (previewVideoRingBuf || previewVideoNVP)
02393         {
02394             VERBOSE(VB_IMPORTANT,
02395                     "PlaybackBox::startPlayer(): Error, last preview window "
02396                     "didn't clean up. Not starting a new preview.");
02397             return;
02398         }
02399 
02400         previewVideoRingBuf = new RingBuffer(rec->pathname, false, false, 1);
02401         if (!previewVideoRingBuf->IsOpen())
02402         {
02403             VERBOSE(VB_IMPORTANT, LOC_ERR +
02404                     "Could not open file for preview video.");
02405             delete previewVideoRingBuf;
02406             previewVideoRingBuf = NULL;
02407             previewVideoBrokenRecId = rec->recordid;
02408             return;
02409         }
02410         previewVideoBrokenRecId = 0;
02411 
02412         previewVideoNVP = new NuppelVideoPlayer("preview player");
02413         previewVideoNVP->SetRingBuffer(previewVideoRingBuf);
02414         previewVideoNVP->SetAsPIP();
02415         QString filters = "";
02416         previewVideoNVP->SetVideoFilters(filters);
02417 
02418         previewVideoThreadRunning = true;
02419         pthread_create(&previewVideoThread, NULL,
02420                        SpawnPreviewVideoThread, previewVideoNVP);
02421 
02422         previewVideoPlayingTimer.start();
02423 
02424         previewVideoState = kStarting;
02425 
02426         int previewRate = 30;
02427         if (gContext->GetNumSetting("PlaybackPreviewLowCPU", 0))
02428         {
02429             previewRate = 12;
02430         }
02431 
02432         previewVideoRefreshTimer->start(1000 / previewRate);
02433     }
02434 }
02435 
02436 void PlaybackBox::playSelectedPlaylist(bool random)
02437 {
02438     previewVideoState = kStopping;
02439 
02440     if (!curitem)
02441         return;
02442 
02443     ProgramInfo *tmpItem;
02444     QStringList::Iterator it = playList.begin();
02445     QStringList randomList = playList;
02446     bool playNext = true;
02447     int i = 0;
02448 
02449     while (randomList.count() && playNext)
02450     {
02451         if (random)
02452             i = (int)(1.0 * randomList.count() * rand() / (RAND_MAX + 1.0));
02453 
02454         it = randomList.at(i);
02455         tmpItem = findMatchingProg(*it);
02456         if (tmpItem)
02457         {
02458             ProgramInfo *rec = new ProgramInfo(*tmpItem);
02459             if ((rec->availableStatus == asAvailable) ||
02460                 (rec->availableStatus == asNotYetAvailable))
02461                 playNext = play(rec, true);
02462             delete rec;
02463         }
02464         randomList.remove(it);
02465     }
02466 }
02467 
02468 void PlaybackBox::playSelected()
02469 {
02470     previewVideoState = kStopping;
02471 
02472     if (!curitem)
02473         return;
02474 
02475     if (m_player && m_player->IsSameProgram(curitem))
02476     {
02477         exitWin();
02478         return;
02479     }
02480 
02481     if ((curitem->availableStatus == asAvailable) ||
02482         (curitem->availableStatus == asNotYetAvailable))
02483         play(curitem);
02484     else
02485         showAvailablePopup(curitem);
02486 
02487     if (m_player)
02488     {
02489         pbbIsVisibleCond.wakeAll();
02490         accept();
02491     }
02492 }
02493 
02494 void PlaybackBox::stopSelected()
02495 {
02496     previewVideoState = kStopping;
02497 
02498     if (!curitem)
02499         return;
02500 
02501     stop(curitem);
02502 }
02503 
02504 void PlaybackBox::deleteSelected()
02505 {
02506     previewVideoState = kStopping;
02507 
02508     if (!curitem)
02509         return;
02510 
02511     bool undelete_possible =
02512             gContext->GetNumSetting("AutoExpireInsteadOfDelete", 0);
02513 
02514     if (curitem->recgroup == "Deleted" && undelete_possible)
02515         doRemove(curitem, false, false);
02516     else if ((curitem->availableStatus != asPendingDelete) &&
02517         (REC_CAN_BE_DELETED(curitem)))
02518         remove(curitem);
02519     else
02520         showAvailablePopup(curitem);
02521 }
02522 
02523 void PlaybackBox::upcoming()
02524 {
02525     previewVideoState = kStopping;
02526 
02527     if (!curitem)
02528         return;
02529 
02530     if (curitem->availableStatus != asAvailable)
02531     {
02532         showAvailablePopup(curitem);
02533         return;
02534     }
02535 
02536     ProgLister *pl = new ProgLister(plTitle, curitem->title, "",
02537                                    gContext->GetMainWindow(), "proglist");
02538     pl->exec();
02539     delete pl;
02540 }
02541 
02542 void PlaybackBox::customEdit()
02543 {
02544     previewVideoState = kStopping;
02545 
02546     if (!curitem)
02547         return;
02548 
02549     if (curitem->availableStatus != asAvailable)
02550     {
02551         showAvailablePopup(curitem);
02552         return;
02553     }
02554     ProgramInfo *pi = curitem;
02555 
02556     if (!pi)
02557         return;
02558 
02559     CustomEdit *ce = new CustomEdit(gContext->GetMainWindow(),
02560                                     "customedit", pi);
02561     ce->exec();
02562     delete ce;
02563 }
02564 
02565 void PlaybackBox::details()
02566 {
02567     previewVideoState = kStopping;
02568 
02569     if (!curitem)
02570         return;
02571 
02572     if (curitem->availableStatus != asAvailable)
02573         showAvailablePopup(curitem);
02574     else
02575         curitem->showDetails();
02576 }
02577 
02578 void PlaybackBox::selected()
02579 {
02580     previewVideoState = kStopping;
02581 
02582     if (inTitle && haveGroupInfoSet)
02583     {
02584         cursorRight();
02585         return;
02586     }
02587 
02588     if (!curitem)
02589         return;
02590 
02591     switch (type)
02592     {
02593         case Play: playSelected(); break;
02594         case Delete: deleteSelected(); break;
02595     }
02596 }
02597 
02598 void PlaybackBox::showMenu()
02599 {
02600     killPlayerSafe();
02601 
02602     popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
02603                              drawPopupFgColor, drawPopupBgColor,
02604                              drawPopupSelColor, "menu popup");
02605 
02606     QLabel *label = popup->addLabel(tr("Recording List Menu"),
02607                                   MythPopupBox::Large, false);
02608     label->setAlignment(Qt::AlignCenter | Qt::WordBreak);
02609 
02610     QButton *topButton = popup->addButton(tr("Change Group Filter"), this,
02611                      SLOT(showRecGroupChooser()));
02612 
02613     popup->addButton(tr("Change Group View"), this,
02614                      SLOT(showViewChanger()));
02615 
02616     if (recGroupType[recGroup] == "recgroup")
02617         popup->addButton(tr("Change Group Password"), this,
02618                          SLOT(showRecGroupPasswordChanger()));
02619 
02620     if (playList.count())
02621     {
02622         popup->addButton(tr("Playlist options"), this,
02623                          SLOT(showPlaylistPopup()));
02624     }
02625     else if (!m_player)
02626     {
02627         if (inTitle)
02628         {
02629             popup->addButton(tr("Add this Group to Playlist"), this,
02630                              SLOT(togglePlayListTitle()));
02631         }
02632         else if (curitem && curitem->availableStatus == asAvailable)
02633         {
02634             popup->addButton(tr("Add this recording to Playlist"), this,
02635                              SLOT(togglePlayListItem()));
02636         }
02637     }
02638 
02639     popup->addButton(tr("Help (Status Icons)"), this,
02640                          SLOT(showIconHelp()));
02641 
02642     popup->ShowPopup(this, SLOT(PopupDone(int)));
02643 
02644     topButton->setFocus();
02645 
02646     expectingPopup = true;
02647 }
02648 
02649 void PlaybackBox::showActionsSelected()
02650 {
02651     if (!curitem)
02652         return;
02653 
02654     if (inTitle && haveGroupInfoSet)
02655         return;
02656 
02657     if ((curitem->availableStatus != asAvailable) &&
02658         (curitem->availableStatus != asFileNotFound))
02659         showAvailablePopup(curitem);
02660     else
02661         showActions(curitem);
02662 }
02663 
02664 bool PlaybackBox::play(ProgramInfo *rec, bool inPlaylist)
02665 {
02666     bool playCompleted = false;
02667     ProgramInfo *tmpItem = NULL;
02668 
02669     if (!rec)
02670         return false;
02671 
02672     if (m_player)
02673         return true;
02674 
02675     rec->pathname = rec->GetPlaybackURL(true);
02676 
02677     if (rec->availableStatus == asNotYetAvailable)
02678     {
02679         tmpItem = findMatchingProg(rec);
02680         if (tmpItem)
02681             tmpItem->availableStatus = asAvailable;
02682     }
02683 
02684     if (fileExists(rec) == false)
02685     {
02686         QString msg =
02687             QString("PlaybackBox::play(): Error, %1 file not found")
02688             .arg(rec->pathname);
02689         VERBOSE(VB_IMPORTANT, msg);
02690 
02691         tmpItem = (tmpItem) ? tmpItem : findMatchingProg(rec);
02692 
02693         if (tmpItem)
02694         {
02695             if (tmpItem->recstatus == rsRecording)
02696                 tmpItem->availableStatus = asNotYetAvailable;
02697             else
02698                 tmpItem->availableStatus = asFileNotFound;
02699 
02700             showAvailablePopup(tmpItem);
02701         }
02702 
02703         return false;
02704     }
02705 
02706     if ((rec->filesize == 0) && (rec->GetFilesize() == 0))
02707     {
02708         VERBOSE(VB_IMPORTANT,
02709             QString("PlaybackBox::play(): Error, %1 is zero-bytes in size")
02710             .arg(rec->pathname));
02711 
02712         tmpItem = (tmpItem) ? tmpItem : findMatchingProg(rec);
02713 
02714         if (tmpItem)
02715         {
02716             if (tmpItem->recstatus == rsRecording)
02717                 tmpItem->availableStatus = asNotYetAvailable;
02718             else
02719                 tmpItem->availableStatus = asZeroByte;
02720 
02721             showAvailablePopup(tmpItem);
02722         }
02723 
02724         return false;
02725     }
02726 
02727     ProgramInfo *tvrec = new ProgramInfo(*rec);
02728 
02729     setEnabled(false);
02730     previewVideoState = kKilling; // stop preview playback and don't restart it
02731     playingSomething = true;
02732 
02733     playCompleted = TV::StartTV(tvrec, false, inPlaylist, underNetworkControl);
02734 
02735     playingSomething = false;
02736     setEnabled(true);
02737 
02738 
02739     previewVideoState = kStarting; // restart playback preview
02740 
02741     delete tvrec;
02742 
02743     connected = FillList();
02744 
02745     return playCompleted;
02746 }
02747 
02748 void PlaybackBox::stop(ProgramInfo *rec)
02749 {
02750     RemoteStopRecording(rec);
02751 }
02752 
02753 bool PlaybackBox::doRemove(ProgramInfo *rec, bool forgetHistory,
02754                            bool forceMetadataDelete)
02755 {
02756     previewVideoBrokenRecId = rec->recordid;
02757     killPlayerSafe();
02758 
02759     if (playList.grep(rec->MakeUniqueKey()).count())
02760         togglePlayListItem(rec);
02761 
02762     if (!forceMetadataDelete)
02763         rec->UpdateLastDelete(true);
02764 
02765     return RemoteDeleteRecording(rec, forgetHistory, forceMetadataDelete);
02766 }
02767 
02768 void PlaybackBox::remove(ProgramInfo *toDel)
02769 {
02770     previewVideoState = kStopping;
02771 
02772     if (delitem)
02773         delete delitem;
02774 
02775     delitem = new ProgramInfo(*toDel);
02776     showDeletePopup(delitem, DeleteRecording);
02777 }
02778 
02779 void PlaybackBox::showActions(ProgramInfo *toExp)
02780 {
02781     killPlayer();
02782 
02783     if (delitem)
02784         delete delitem;
02785 
02786     delitem = new ProgramInfo(*toExp);
02787 
02788     if (fileExists(delitem) == false)
02789     {
02790         QString msg =
02791             QString("PlaybackBox::showActions(): Error, %1 file not found")
02792             .arg(delitem->pathname);
02793         VERBOSE(VB_IMPORTANT, msg);
02794 
02795         ProgramInfo *tmpItem = findMatchingProg(delitem);
02796         if (tmpItem)
02797         {
02798             tmpItem->availableStatus = asFileNotFound;
02799             showFileNotFoundActionPopup(delitem);
02800         }
02801     }
02802     else if (delitem->availableStatus != asAvailable)
02803         showAvailablePopup(delitem);
02804     else
02805         showActionPopup(delitem);
02806 }
02807 
02808 void PlaybackBox::showDeletePopup(ProgramInfo *program, deletePopupType types)
02809 {
02810     freeSpaceNeedsUpdate = true;
02811 
02812     popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
02813                              drawPopupFgColor, drawPopupBgColor,
02814                              drawPopupSelColor, "delete popup");
02815     QString message1 = "";
02816     QString message2 = "";
02817     switch (types)
02818     {
02819         case DeleteRecording:
02820              message1 = tr("Are you sure you want to delete:"); break;
02821         case ForceDeleteRecording:
02822              message1 = tr("ERROR: Recorded file does not exist.");
02823              message2 = tr("Are you sure you want to delete:");
02824              break;
02825         case StopRecording:
02826              message1 = tr("Are you sure you want to stop:"); break;
02827     }
02828 
02829     initPopup(popup, program, message1, message2);
02830 
02831     QString tmpmessage;
02832     const char *tmpslot = NULL;
02833 
02834     if ((types == DeleteRecording) &&
02835         (program->IsSameProgram(*program)) &&
02836         (program->recgroup != "LiveTV"))
02837     {
02838         tmpmessage = tr("Yes, and allow re-record");
02839         tmpslot = SLOT(doDeleteForgetHistory());
02840         popup->addButton(tmpmessage, this, tmpslot);
02841     }
02842 
02843     switch (types)
02844     {
02845         case DeleteRecording:
02846              tmpmessage = tr("Yes, delete it");
02847              tmpslot = SLOT(doDelete());
02848              break;
02849         case ForceDeleteRecording:
02850              tmpmessage = tr("Yes, delete it");
02851              tmpslot = SLOT(doForceDelete());
02852              break;
02853         case StopRecording:
02854              tmpmessage = tr("Yes, stop recording it");
02855              tmpslot = SLOT(doStop());
02856              break;
02857     }
02858 
02859     QButton *yesButton = popup->addButton(tmpmessage, this, tmpslot);
02860 
02861     switch (types)
02862     {
02863         case DeleteRecording:
02864         case ForceDeleteRecording:
02865              tmpmessage = tr("No, keep it, I changed my mind");
02866              tmpslot = SLOT(noDelete());
02867              break;
02868         case StopRecording:
02869              tmpmessage = tr("No, continue recording it");
02870              tmpslot = SLOT(noStop());
02871              break;
02872     }
02873     QButton *noButton = popup->addButton(tmpmessage, this, tmpslot);
02874 
02875     if (types == DeleteRecording ||
02876         types == ForceDeleteRecording)
02877         noButton->setFocus();
02878     else
02879     {
02880         if (program->GetAutoExpireFromRecorded())
02881             yesButton->setFocus();
02882         else
02883             noButton->setFocus();
02884     }
02885 
02886     popup->ShowPopup(this, SLOT(PopupDone(int)));
02887 
02888     expectingPopup = true;
02889 }
02890 
02891 void PlaybackBox::showAvailablePopup(ProgramInfo *rec)
02892 {
02893     if (!rec)
02894         return;
02895 
02896     QString msg = rec->title + "\n";
02897     if (rec->subtitle != "")
02898         msg += rec->subtitle + "\n";
02899     msg += "\n";
02900 
02901     switch (rec->availableStatus)
02902     {
02903         case asAvailable:
02904                  if (rec->programflags & (FL_INUSERECORDING | FL_INUSEPLAYING))
02905                  {
02906                      QString byWho;
02907                      rec->IsInUse(byWho);
02908 
02909                      MythPopupBox::showOkPopup(gContext->GetMainWindow(),
02910                                    QObject::tr("Recording Available"), msg +
02911                                    QObject::tr("This recording is currently in "
02912                                                "use by:") + "\n" + byWho);
02913                  }
02914                  else
02915                  {
02916                      MythPopupBox::showOkPopup(gContext->GetMainWindow(),
02917                                    QObject::tr("Recording Available"), msg +
02918                                    QObject::tr("This recording is currently "
02919                                                "Available"));
02920                  }
02921                  break;
02922         case asPendingDelete:
02923                  MythPopupBox::showOkPopup(gContext->GetMainWindow(),
02924                                QObject::tr("Recording Unavailable"), msg +
02925                                QObject::tr("This recording is currently being "
02926                                            "deleted and is unavailable"));
02927                  break;
02928         case asFileNotFound:
02929                  MythPopupBox::showOkPopup(gContext->GetMainWindow(),
02930                                QObject::tr("Recording Unavailable"), msg +
02931                                QObject::tr("The file for this recording can "
02932                                            "not be found"));
02933                  break;
02934         case asZeroByte:
02935                  MythPopupBox::showOkPopup(gContext->GetMainWindow(),
02936                                QObject::tr("Recording Unavailable"), msg +
02937                                QObject::tr("The file for this recording is "
02938                                            "empty."));
02939                  break;
02940         case asNotYetAvailable:
02941                  MythPopupBox::showOkPopup(gContext->GetMainWindow(),
02942                                QObject::tr("Recording Unavailable"), msg +
02943                                QObject::tr("This recording is not yet "
02944                                            "available."));
02945     }
02946 }
02947 
02948 void PlaybackBox::showPlaylistPopup()
02949 {
02950     if (expectingPopup)
02951        cancelPopup();
02952 
02953     popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
02954                              drawPopupFgColor, drawPopupBgColor,
02955                              drawPopupSelColor, "playlist popup");
02956 
02957     QLabel *tlabel = NULL;
02958     if (playList.count() > 1)
02959     {
02960         tlabel = popup->addLabel(tr("There are %1 items in the playlist.")
02961                                        .arg(playList.count()));
02962     } else {
02963         tlabel = popup->addLabel(tr("There is %1 item in the playlist.")
02964                                        .arg(playList.count()));
02965     }
02966     tlabel->setAlignment(Qt::AlignCenter | Qt::WordBreak);
02967 
02968     QButton *playButton = popup->addButton(tr("Play"), this, SLOT(doPlayList()));
02969 
02970     popup->addButton(tr("Shuffle Play"), this, SLOT(doPlayListRandom()));
02971     popup->addButton(tr("Clear Playlist"), this, SLOT(doClearPlaylist()));
02972 
02973     if (inTitle)
02974     {
02975         if ((viewMask & VIEW_TITLES))
02976             popup->addButton(tr("Toggle playlist for this Category/Title"),
02977                              this, SLOT(togglePlayListTitle()));
02978         else
02979             popup->addButton(tr("Toggle playlist for this Recording Group"),
02980                              this, SLOT(togglePlayListTitle()));
02981     }
02982     else
02983     {
02984         popup->addButton(tr("Toggle playlist for this recording"), this,
02985                          SLOT(togglePlayListItem()));
02986     }
02987 
02988     QLabel *label = popup->addLabel(
02989                         tr("These actions affect all items in the playlist"));
02990     label->setAlignment(Qt::AlignCenter | Qt::WordBreak);
02991 
02992     popup->addButton(tr("Change Recording Group"), this,
02993                      SLOT(doPlaylistChangeRecGroup()));
02994     popup->addButton(tr("Change Playback Group"), this,
02995                      SLOT(doPlaylistChangePlayGroup()));
02996     popup->addButton(tr("Job Options"), this,
02997                      SLOT(showPlaylistJobPopup()));
02998     popup->addButton(tr("Delete"), this, SLOT(doPlaylistDelete()));
02999     popup->addButton(tr("Delete, and allow re-record"), this,
03000                      SLOT(doPlaylistDeleteForgetHistory()));
03001 
03002     playButton->setFocus();
03003 
03004     popup->ShowPopup(this, SLOT(PopupDone(int)));
03005 
03006     expectingPopup = true;
03007 }
03008 
03009 void PlaybackBox::showPlaylistJobPopup()
03010 {
03011     if (expectingPopup)
03012        cancelPopup();
03013 
03014     popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
03015                              drawPopupFgColor, drawPopupBgColor,
03016                              drawPopupSelColor, "playlist popup");
03017 
03018     QLabel *tlabel = NULL;
03019     if (playList.count() > 1)
03020     {
03021         tlabel = popup->addLabel(tr("There are %1 items in the playlist.")
03022                                        .arg(playList.count()));
03023     } else {
03024         tlabel = popup->addLabel(tr("There is %1 item in the playlist.")
03025                                        .arg(playList.count()));
03026     }
03027     tlabel->setAlignment(Qt::AlignCenter | Qt::WordBreak);
03028 
03029     QButton *jobButton;
03030     QString jobTitle = "";
03031     QString command = "";
03032     QStringList::Iterator it;
03033     ProgramInfo *tmpItem;
03034     bool isTranscoding = true;
03035     bool isFlagging = true;
03036     bool isRunningUserJob1 = true;
03037     bool isRunningUserJob2 = true;
03038     bool isRunningUserJob3 = true;
03039     bool isRunningUserJob4 = true;
03040 
03041     for(it = playList.begin(); it != playList.end(); ++it)
03042     {
03043         tmpItem = findMatchingProg(*it);
03044         if (tmpItem) {
03045             if (!JobQueue::IsJobQueuedOrRunning(JOB_TRANSCODE,
03046                                        tmpItem->chanid, tmpItem->recstartts))
03047                 isTranscoding = false;
03048             if (!JobQueue::IsJobQueuedOrRunning(JOB_COMMFLAG,
03049                                        tmpItem->chanid, tmpItem->recstartts))
03050                 isFlagging = false;
03051             if (!JobQueue::IsJobQueuedOrRunning(JOB_USERJOB1,
03052                                        tmpItem->chanid, tmpItem->recstartts))
03053                 isRunningUserJob1 = false;
03054             if (!JobQueue::IsJobQueuedOrRunning(JOB_USERJOB2,
03055                                        tmpItem->chanid, tmpItem->recstartts))
03056                 isRunningUserJob2 = false;
03057             if (!JobQueue::IsJobQueuedOrRunning(JOB_USERJOB3,
03058                                        tmpItem->chanid, tmpItem->recstartts))
03059                 isRunningUserJob3 = false;
03060             if (!JobQueue::IsJobQueuedOrRunning(JOB_USERJOB4,
03061                                        tmpItem->chanid, tmpItem->recstartts))
03062                 isRunningUserJob4 = false;
03063             if (!isTranscoding && !isFlagging && !isRunningUserJob1 &&
03064                 !isRunningUserJob2 && !isRunningUserJob3 && !isRunningUserJob4)
03065                 break;
03066         }
03067     }
03068     if (!isTranscoding)
03069         jobButton = popup->addButton(tr("Begin Transcoding"), this,
03070                          SLOT(doPlaylistBeginTranscoding()));
03071     else
03072         jobButton = popup->addButton(tr("Stop Transcoding"), this,
03073                          SLOT(stopPlaylistTranscoding()));
03074     if (!isFlagging)
03075         popup->addButton(tr("Begin Commercial Flagging"), this,
03076                          SLOT(doPlaylistBeginFlagging()));
03077     else
03078         popup->addButton(tr("Stop Commercial Flagging"), this,
03079                          SLOT(stopPlaylistFlagging()));
03080 
03081     command = gContext->GetSetting("UserJob1", "");
03082     if (command != "") {
03083         jobTitle = gContext->GetSetting("UserJobDesc1");
03084 
03085         if (!isRunningUserJob1)
03086             popup->addButton(tr("Begin") + " " + jobTitle, this,
03087                              SLOT(doPlaylistBeginUserJob1()));
03088         else
03089             popup->addButton(tr("Stop") + " " + jobTitle, this,
03090                              SLOT(stopPlaylistUserJob1()));
03091     }
03092 
03093     command = gContext->GetSetting("UserJob2", "");
03094     if (command != "") {
03095         jobTitle = gContext->GetSetting("UserJobDesc2");
03096 
03097         if (!isRunningUserJob2)
03098             popup->addButton(tr("Begin") + " " + jobTitle, this,
03099                              SLOT(doPlaylistBeginUserJob2()));
03100         else
03101             popup->addButton(tr("Stop") + " " + jobTitle, this,
03102                              SLOT(stopPlaylistUserJob2()));
03103     }
03104 
03105     command = gContext->GetSetting("UserJob3", "");
03106     if (command != "") {
03107         jobTitle = gContext->GetSetting("UserJobDesc3");
03108 
03109         if (!isRunningUserJob3)
03110             popup->addButton(tr("Begin") + " " + jobTitle, this,
03111                              SLOT(doPlaylistBeginUserJob3()));
03112         else
03113             popup->addButton(tr("Stop") + " " + jobTitle, this,
03114                              SLOT(stopPlaylistUserJob3()));
03115     }
03116 
03117     command = gContext->GetSetting("UserJob4", "");
03118     if (command != "") {
03119         jobTitle = gContext->GetSetting("UserJobDesc4");
03120 
03121         if (!isRunningUserJob4)
03122             popup->addButton(tr("Begin") + " " + jobTitle, this,
03123                              SLOT(doPlaylistBeginUserJob4()));
03124         else
03125             popup->addButton(tr("Stop") + " " + jobTitle, this,
03126                              SLOT(stopPlaylistUserJob4()));
03127     }
03128 
03129     popup->ShowPopup(this, SLOT(PopupDone(int)));
03130     jobButton->setFocus();
03131 
03132     expectingPopup = true;
03133 }
03134 
03135 void PlaybackBox::showPlayFromPopup()
03136 {
03137     if (expectingPopup)
03138         cancelPopup();
03139 
03140     popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
03141                              drawPopupFgColor, drawPopupBgColor,
03142                              drawPopupSelColor, "playfrom popup");
03143 
03144     initPopup(popup, delitem, "", "");
03145 
03146     QButton *playButton = popup->addButton(tr("Play from bookmark"), this,
03147             SLOT(doPlay()));
03148     popup->addButton(tr("Play from beginning"), this, SLOT(doPlayFromBeg()));
03149 
03150     popup->ShowPopup(this, SLOT(PopupDone(int)));
03151     playButton->setFocus();
03152 
03153     expectingPopup = true;
03154 }
03155 
03156 void PlaybackBox::showStoragePopup()
03157 {
03158     if (expectingPopup)
03159         cancelPopup();
03160 
03161     popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
03162                              drawPopupFgColor, drawPopupBgColor,
03163                              drawPopupSelColor, "storage popup");
03164 
03165     initPopup(popup, delitem, "", "");
03166 
03167     QButton *storageButton;
03168 
03169     MythPushButton *toggleButton;
03170 
03171     storageButton = popup->addButton(tr("Change Recording Group"), this,
03172                                      SLOT(showRecGroupChanger()));
03173 
03174     popup->addButton(tr("Change Playback Group"), this,
03175                      SLOT(showPlayGroupChanger()));
03176 
03177     if (delitem)
03178     {
03179         toggleButton = new MythPushButton(
03180             tr("Disable Auto Expire"), tr("Enable Auto Expire"),
03181             popup, delitem->GetAutoExpireFromRecorded());
03182         connect(toggleButton, SIGNAL(toggled(bool)), this,
03183                 SLOT(toggleAutoExpire(bool)));
03184         popup->addWidget(toggleButton, false);
03185 
03186         toggleButton = new MythPushButton(
03187             tr("Do not preserve this episode"), tr("Preserve this episode"),
03188             popup, delitem->GetPreserveEpisodeFromRecorded());
03189         connect(toggleButton, SIGNAL(toggled(bool)), this,
03190                 SLOT(togglePreserveEpisode(bool)));
03191         popup->addWidget(toggleButton, false);
03192     }
03193 
03194     popup->ShowPopup(this, SLOT(PopupDone(int)));
03195     storageButton->setFocus();
03196 
03197     expectingPopup = true;
03198 }
03199 
03200 void PlaybackBox::showRecordingPopup()
03201 {
03202     if (expectingPopup)
03203         cancelPopup();
03204 
03205     popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
03206                              drawPopupFgColor, drawPopupBgColor,
03207                              drawPopupSelColor, "recording popup");
03208 
03209     initPopup(popup, delitem, "", "");
03210 
03211     QButton *editButton = popup->addButton(tr("Edit Recording Schedule"), this,
03212                      SLOT(doEditScheduled()));
03213 
03214     popup->addButton(tr("Allow this program to re-record"), this,
03215                      SLOT(doAllowRerecord()));
03216 
03217     popup->addButton(tr("Show Program Details"), this,
03218                      SLOT(showProgramDetails()));
03219 
03220     popup->addButton(tr("Change Recording Title"), this,
03221                      SLOT(showRecTitleChanger()));
03222 
03223     popup->ShowPopup(this, SLOT(PopupDone(int)));
03224     editButton->setFocus();
03225 
03226     expectingPopup = true;
03227 }
03228 
03229 void PlaybackBox::showJobPopup()
03230 {
03231     if (expectingPopup)
03232         cancelPopup();
03233 
03234     if (!curitem)
03235         return;
03236 
03237     popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
03238                              drawPopupFgColor, drawPopupBgColor,
03239                              drawPopupSelColor, "job popup");
03240 
03241     initPopup(popup, delitem, "", "");
03242 
03243     QButton *jobButton;
03244     QString jobTitle = "";
03245     QString command = "";
03246 
03247     if (JobQueue::IsJobQueuedOrRunning(JOB_TRANSCODE, curitem->chanid,
03248                                                   curitem->recstartts))
03249         jobButton = popup->addButton(tr("Stop Transcoding"), this,
03250                          SLOT(doBeginTranscoding()));
03251     else
03252         jobButton = popup->addButton(tr("Begin Transcoding"), this,
03253                          SLOT(showTranscodingProfiles()));
03254 
03255     if (JobQueue::IsJobQueuedOrRunning(JOB_COMMFLAG, curitem->chanid,
03256                                                   curitem->recstartts))
03257         popup->addButton(tr("Stop Commercial Flagging"), this,
03258                          SLOT(doBeginFlagging()));
03259     else
03260         popup->addButton(tr("Begin Commercial Flagging"), this,
03261                          SLOT(doBeginFlagging()));
03262 
03263     command = gContext->GetSetting("UserJob1", "");
03264     if (command != "") {
03265         jobTitle = gContext->GetSetting("UserJobDesc1", tr("User Job") + " #1");
03266 
03267         if (JobQueue::IsJobQueuedOrRunning(JOB_USERJOB1, curitem->chanid,
03268                                    curitem->recstartts))
03269             popup->addButton(tr("Stop") + " " + jobTitle, this,
03270                              SLOT(doBeginUserJob1()));
03271         else
03272             popup->addButton(tr("Begin") + " " + jobTitle, this,
03273                              SLOT(doBeginUserJob1()));
03274     }
03275 
03276     command = gContext->GetSetting("UserJob2", "");
03277     if (command != "") {
03278         jobTitle = gContext->GetSetting("UserJobDesc2", tr("User Job") + " #2");
03279 
03280         if (JobQueue::IsJobQueuedOrRunning(JOB_USERJOB2, curitem->chanid,
03281                                    curitem->recstartts))
03282             popup->addButton(tr("Stop") + " " + jobTitle, this,
03283                              SLOT(doBeginUserJob2()));
03284         else
03285             popup->addButton(tr("Begin") + " " + jobTitle, this,
03286                              SLOT(doBeginUserJob2()));
03287     }
03288 
03289     command = gContext->GetSetting("UserJob3", "");
03290     if (command != "") {
03291         jobTitle = gContext->GetSetting("UserJobDesc3", tr("User Job") + " #3");
03292 
03293         if (JobQueue::IsJobQueuedOrRunning(JOB_USERJOB3, curitem->chanid,
03294                                    curitem->recstartts))
03295             popup->addButton(tr("Stop") + " " + jobTitle, this,
03296                              SLOT(doBeginUserJob3()));
03297         else
03298             popup->addButton(tr("Begin") + " " + jobTitle, this,
03299                              SLOT(doBeginUserJob3()));
03300     }
03301 
03302     command = gContext->GetSetting("UserJob4", "");
03303     if (command != "") {
03304         jobTitle = gContext->GetSetting("UserJobDesc4", tr("User Job") + " #4");
03305 
03306         if (JobQueue::IsJobQueuedOrRunning(JOB_USERJOB4, curitem->chanid,
03307                                    curitem->recstartts))
03308             popup->addButton(tr("Stop") + " " + jobTitle, this,
03309                              SLOT(doBeginUserJob4()));
03310         else
03311             popup->addButton(tr("Begin") + " "  + jobTitle, this,
03312                              SLOT(doBeginUserJob4()));
03313     }
03314 
03315     popup->ShowPopup(this, SLOT(PopupDone(int)));
03316     jobButton->setFocus();
03317 
03318     expectingPopup = true;
03319 }
03320 
03321 void PlaybackBox::showTranscodingProfiles()
03322 {
03323     if (expectingPopup)
03324         cancelPopup();
03325 
03326     if (!curitem)
03327         return;
03328 
03329     popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
03330                              drawPopupFgColor, drawPopupBgColor,
03331                              drawPopupSelColor, "transcode popup");
03332 
03333     initPopup(popup, delitem, "", "");
03334 
03335     QButton *defaultButton;
03336 
03337     defaultButton = popup->addButton(tr("Default"), this,
03338                                  SLOT(doBeginTranscoding()));
03339     popup->addButton(tr("Autodetect"), this,
03340                      SLOT(changeProfileAndTranscodeAuto()));
03341     popup->addButton(tr("High Quality"), this,
03342                      SLOT(changeProfileAndTranscodeHigh()));
03343     popup->addButton(tr("Medium Quality"), this,
03344                      SLOT(changeProfileAndTranscodeMedium()));
03345     popup->addButton(tr("Low Quality"), this,
03346                      SLOT(changeProfileAndTranscodeLow()));
03347 
03348     popup->ShowPopup(this, SLOT(PopupDone(int)));
03349     defaultButton->setFocus();
03350 
03351     expectingPopup = true;
03352 }
03353 
03354 void PlaybackBox::changeProfileAndTranscode(QString profile)
03355 {
03356     curitem->ApplyTranscoderProfileChange(profile);
03357     doBeginTranscoding();
03358 }
03359 
03360 void PlaybackBox::showActionPopup(ProgramInfo *program)
03361 {
03362     if (!curitem || !program)
03363         return;
03364 
03365     popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
03366                              drawPopupFgColor, drawPopupBgColor,
03367                              drawPopupSelColor, "action popup");
03368 
03369     initPopup(popup, program, "", "");
03370 
03371     QButton *playButton;
03372 
03373     if (!(m_player && m_player->IsSameProgram(curitem)))
03374     {
03375         if (curitem->programflags & FL_BOOKMARK)
03376             playButton = popup->addButton(tr("Play from..."), this,
03377                                         SLOT(showPlayFromPopup()));
03378         else
03379             playButton = popup->addButton(tr("Play"), this, SLOT(doPlay()));
03380     }
03381 
03382     if (!m_player)
03383     {
03384         if (playList.grep(curitem->MakeUniqueKey()).count())
03385             popup->addButton(tr("Remove from Playlist"), this,
03386                             SLOT(togglePlayListItem()));
03387         else
03388             popup->addButton(tr("Add to Playlist"), this,
03389                             SLOT(togglePlayListItem()));
03390     }
03391 
03392     TVState m_tvstate = kState_None;
03393     if (m_player)
03394         m_tvstate = m_player->GetState();
03395 
03396     if (program->recstatus == rsRecording &&
03397         (!(m_player &&
03398             (m_tvstate == kState_WatchingLiveTV ||
03399             m_tvstate == kState_WatchingRecording) &&
03400             m_player->IsSameProgram(curitem))))
03401     {
03402         popup->addButton(tr("Stop Recording"), this, SLOT(askStop()));
03403     }
03404 
03405     if (curitem->programflags & FL_WATCHED)
03406         popup->addButton(tr("Mark as Unwatched"), this,
03407                                     SLOT(setUnwatched()));
03408     else
03409         popup->addButton(tr("Mark as Watched"), this,
03410                                     SLOT(setWatched()));
03411 
03412     popup->addButton(tr("Storage Options"), this, SLOT(showStoragePopup()));
03413     popup->addButton(tr("Recording Options"), this, SLOT(showRecordingPopup()));
03414     popup->addButton(tr("Job Options"), this, SLOT(showJobPopup()));
03415 
03416     if (!(m_player && m_player->IsSameProgram(curitem)))
03417     {
03418         if (curitem->recgroup == "Deleted")
03419         {
03420             popup->addButton(tr("Undelete"), this,
03421                         SLOT(doUndelete()));
03422             popup->addButton(tr("Delete Forever"), this,
03423                         SLOT(doDelete()));
03424         }
03425         else
03426         {
03427             popup->addButton(tr("Delete"), this,
03428                         SLOT(askDelete()));
03429         }
03430     }
03431 
03432     popup->ShowPopup(this, SLOT(PopupDone(int)));
03433 
03434     if (!m_player || !m_player->IsSameProgram(curitem))
03435     {
03436         if (playButton)
03437             playButton->setFocus();
03438     }
03439 
03440     expectingPopup = true;
03441 }
03442 
03443 void PlaybackBox::showFileNotFoundActionPopup(ProgramInfo *program)
03444 {
03445     if (!curitem || !program)
03446         return;
03447 
03448     popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
03449                              drawPopupFgColor, drawPopupBgColor,
03450                              drawPopupSelColor, "action popup");
03451 
03452     QString msg = QObject::tr("Recording Unavailable") + "\n";
03453     msg += QObject::tr("The file for this recording can "
03454                        "not be found") + "\n";
03455 
03456     initPopup(popup, program, "", msg);
03457 
03458     QButton *detailsButton;
03459     detailsButton = popup->addButton(tr("Show Program Details"), this,
03460                                      SLOT(showProgramDetails()));
03461 
03462     popup->addButton(tr("Delete"), this, SLOT(askDelete()));
03463 
03464     popup->ShowPopup(this, SLOT(PopupDone(int)));
03465 
03466     detailsButton->setFocus();
03467 
03468     expectingPopup = true;
03469 }
03470 
03471 void PlaybackBox::initPopup(MythPopupBox *popup, ProgramInfo *program,
03472                             QString message, QString message2)
03473 {
03474     killPlayerSafe();
03475 
03476     QDateTime recstartts = program->recstartts;
03477     QDateTime recendts = program->recendts;
03478 
03479     QString timedate = recstartts.date().toString(formatLongDate) + QString(", ") +
03480                        recstartts.time().toString(formatTime) + QString(" - ") +
03481                        recendts.time().toString(formatTime);
03482 
03483     QString descrip = program->description;
03484     descrip = cutDownString(descrip, &defaultMediumFont, (int)(width() / 2));
03485     QString titl = program->title;
03486     titl = cutDownString(titl, &defaultBigFont, (int)(width() / 2));
03487 
03488     if (message.stripWhiteSpace().length() > 0)
03489         popup->addLabel(message);
03490 
03491     popup->addLabel(program->title, MythPopupBox::Large);
03492 
03493     if ((program->subtitle).stripWhiteSpace().length() > 0)
03494         popup->addLabel("\"" + program->subtitle + "\"\n" + timedate);
03495     else
03496         popup->addLabel(timedate);
03497 
03498     if (message2.stripWhiteSpace().length() > 0)
03499         popup->addLabel(message2);
03500 }
03501 
03502 void PlaybackBox::cancelPopup(void)
03503 {
03504     popup->hide();
03505     expectingPopup = false;
03506 
03507     popup->deleteLater();
03508     popup = NULL;
03509 
03510     paintSkipUpdate = false;
03511     paintSkipCount = 2;
03512 
03513     setActiveWindow();
03514 
03515     EmbedTVWindow();
03516 }
03517 
03518 void PlaybackBox::doClearPlaylist(void)
03519 {
03520     if (expectingPopup)
03521         cancelPopup();
03522 
03523     playList.clear();
03524 }
03525 
03526 void PlaybackBox::doPlay(void)
03527 {
03528     if (!expectingPopup)
03529         return;
03530 
03531     cancelPopup();
03532 
03533     if (curitem)
03534         delete curitem;
03535 
03536     curitem = new ProgramInfo(*delitem);
03537 
03538     playSelected();
03539 }
03540 
03541 void PlaybackBox::doPlayFromBeg(void)
03542 {
03543     delitem->setIgnoreBookmark(true);
03544     doPlay();
03545 }
03546 
03547 void PlaybackBox::doPlayList(void)
03548 {
03549     if (!expectingPopup)
03550         return;
03551 
03552     cancelPopup();
03553 
03554     playSelectedPlaylist(false);
03555 }
03556 
03557 
03558 void PlaybackBox::doPlayListRandom(void)
03559 {
03560     if (!expectingPopup)
03561         return;
03562 
03563     cancelPopup();
03564 
03565     playSelectedPlaylist(true);
03566 }
03567 
03568 void PlaybackBox::askStop(void)
03569 {
03570     if (!expectingPopup)
03571         return;
03572 
03573     cancelPopup();
03574 
03575     showDeletePopup(delitem, StopRecording);
03576 }
03577 
03578 void PlaybackBox::noStop(void)
03579 {
03580     if (!expectingPopup)
03581         return;
03582 
03583     cancelPopup();
03584 
03585     previewVideoState = kChanging;
03586 
03587     previewVideoRefreshTimer->start(500);
03588 }
03589 
03590 void PlaybackBox::doStop(void)
03591 {
03592     if (!expectingPopup)
03593         return;
03594 
03595     cancelPopup();
03596 
03597     stop(delitem);
03598 
03599     previewVideoState = kChanging;
03600 
03601     previewVideoRefreshTimer->start(500);
03602 }
03603 
03604 void PlaybackBox::showProgramDetails()
03605 {
03606     if (!expectingPopup)
03607         return;
03608 
03609     cancelPopup();
03610 
03611     if (!curitem)
03612         return;
03613 
03614     curitem->showDetails();
03615 }
03616 
03617 void PlaybackBox::doEditScheduled()
03618 {
03619     if (!expectingPopup)
03620         return;
03621 
03622     cancelPopup();
03623 
03624     if (!curitem)
03625         return;
03626 
03627     if (curitem->availableStatus != asAvailable)
03628     {
03629         showAvailablePopup(curitem);
03630     }
03631     else
03632     {
03633         ScheduledRecording *record = new ScheduledRecording();
03634         ProgramInfo *t_pginfo = new ProgramInfo(*curitem);
03635         record->loadByProgram(t_pginfo);
03636         record->exec();
03637         record->deleteLater();
03638 
03639         connected = FillList();
03640         delete t_pginfo;
03641     }
03642 
03643     EmbedTVWindow();
03644 }
03645 
03652 void PlaybackBox::doAllowRerecord()
03653 {
03654     if (!expectingPopup)
03655         return;
03656 
03657     cancelPopup();
03658 
03659     if (!curitem)
03660         return;
03661 
03662     curitem->ForgetHistory();
03663 }
03664 
03665 void PlaybackBox::doJobQueueJob(int jobType, int jobFlags)
03666 {
03667     if (!expectingPopup)
03668         return;
03669 
03670     cancelPopup();
03671 
03672     if (!curitem)
03673         return;
03674 
03675     ProgramInfo *tmpItem = findMatchingProg(curitem);
03676 
03677     if (JobQueue::IsJobQueuedOrRunning(jobType,