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
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
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
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
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
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
00240 theme(new XMLParse()),
00241
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
00251 popup(NULL), expectingPopup(false),
00252
00253 recGroupLastItem(0), recGroupChooserPassword(""),
00254 recGroupPopup(NULL), recGroupListBox(NULL),
00255 recGroupLineEdit(NULL), recGroupLineEdit1(NULL),
00256 recGroupOldPassword(NULL), recGroupNewPassword(NULL),
00257 recGroupOkButton(NULL),
00258
00259 fillListTimer(new QTimer(this)), fillListFromCache(false),
00260 connected(false),
00261 titleIndex(0), progIndex(0),
00262 progsInDB(0),
00263
00264 curitem(NULL), delitem(NULL),
00265 progCache(NULL), playingSomething(false),
00266
00267 haveGroupInfoSet(false), inTitle(false),
00268 leftRight(false), playbackVideoContainer(false),
00269
00270 freeSpaceNeedsUpdate(true), freeSpaceTimer(new QTimer(this)),
00271 freeSpaceTotal(0), freeSpaceUsed(0),
00272
00273 paintSkipCount(0), paintSkipUpdate(false),
00274
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
00282 previewPixmapEnabled(false), previewPixmap(NULL),
00283 previewSuspend(false), previewChanid(""),
00284 previewGeneratorRunning(0),
00285
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
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
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
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
00397 connected = FillList();
00398
00399
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
00408 previewVideoRefreshTimer->start(500);
00409 previewStartts = QDateTime::currentDateTime();
00410
00411
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
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
00492
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
00515 void PlaybackBox::killPlayerSafe(void)
00516 {
00517 QMutexLocker locker(&previewVideoKillLock);
00518
00519
00520
00521 ignoreKeyPressEvents = true;
00522
00523 while (previewVideoState != kKilled && previewVideoState != kStopped &&
00524 previewVideoThreadRunning)
00525 {
00526
00527 killPlayer();
00528
00529
00530 previewVideoState = (previewVideoState == kKilled) ?
00531 kKilled : kKilling;
00532
00533
00534
00535
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
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
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;
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
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
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
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
01043 if (inTitle && haveGroupInfoSet)
01044 return;
01045
01046
01047
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
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
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
01079
01080 if (previewVideoKillState != kDone && !killPlayer())
01081 return;
01082
01083
01084
01085 if (!previewVideoEnabled &&
01086 (previewVideoState != kKilling) && (previewVideoState != kKilled))
01087 {
01088 previewVideoState = kStopping;
01089 }
01090
01091
01092
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();
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
01147 killPlayer();
01148 return;
01149 }
01150 }
01151
01152 if ((previewVideoState == kStopping) || (previewVideoState == kKilling))
01153 {
01154 if (previewVideoNVP)
01155 {
01156 killPlayer();
01157 return;
01158 }
01159
01160 if (previewVideoState == kKilling)
01161 previewVideoState = kKilled;
01162 else
01163 previewVideoState = kStopped;
01164 }
01165
01166
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
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
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
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
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
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
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
01784
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
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) &&
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 != "")
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 != "")
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])
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
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
02058 delHours[recid] = 1000;
02059 if (last_delete.isValid())
02060 delHours[recid] = last_delete.secsTo(now) / 3600 + 1;
02061
02062
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
02079 if (spanHours[recid] == 0)
02080 {
02081 spanHours[recid] = 1000;
02082 delHours[recid] = 1000;
02083 }
02084
02085
02086 if (p->recordid == 0 || maxEpisodes[recid] > 0)
02087 p->recpriority2 = 0;
02088 else
02089 p->recpriority2 = (recidEpisodes[p->recordid] - 1) * baseValue;
02090
02091
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
02100 if (hrs < 42)
02101 p->recpriority2 += 42 - hrs;
02102
02103
02104 p->recpriority2 += abs((hrs % 24) - 12) * 2;
02105
02106
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
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
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
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
02190
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
02208
02209
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
02240
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
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
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
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
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;
02731 playingSomething = true;
02732
02733 playCompleted = TV::StartTV(tvrec, false, inPlaylist, underNetworkControl);
02734
02735 playingSomething = false;
02736 setEnabled(true);
02737
02738
02739 previewVideoState = kStarting;
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,