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, curitem->chanid,
03678 curitem->recstartts))
03679 {
03680 JobQueue::ChangeJobCmds(jobType, curitem->chanid,
03681 curitem->recstartts, JOB_STOP);
03682 if ((jobType & JOB_COMMFLAG) && (tmpItem))
03683 {
03684 tmpItem->programflags &= ~FL_EDITING;
03685 tmpItem->programflags &= ~FL_COMMFLAG;
03686 }
03687 } else {
03688 QString jobHost = "";
03689 if (gContext->GetNumSetting("JobsRunOnRecordHost", 0))
03690 jobHost = curitem->hostname;
03691
03692 JobQueue::QueueJob(jobType, curitem->chanid, curitem->recstartts,
03693 "", "", jobHost, jobFlags);
03694 }
03695 }
03696
03697 void PlaybackBox::doBeginFlagging()
03698 {
03699 doJobQueueJob(JOB_COMMFLAG);
03700 update(drawListBounds);
03701 }
03702
03703 void PlaybackBox::doPlaylistJobQueueJob(int jobType, int jobFlags)
03704 {
03705 ProgramInfo *tmpItem;
03706 QStringList::Iterator it;
03707 int jobID;
03708
03709 if (expectingPopup)
03710 cancelPopup();
03711
03712 for (it = playList.begin(); it != playList.end(); ++it)
03713 {
03714 jobID = 0;
03715 tmpItem = findMatchingProg(*it);
03716 if (tmpItem &&
03717 (!JobQueue::IsJobQueuedOrRunning(jobType, tmpItem->chanid,
03718 tmpItem->recstartts))) {
03719 QString jobHost = "";
03720 if (gContext->GetNumSetting("JobsRunOnRecordHost", 0))
03721 jobHost = tmpItem->hostname;
03722
03723 JobQueue::QueueJob(jobType, tmpItem->chanid,
03724 tmpItem->recstartts, "", "", jobHost, jobFlags);
03725 }
03726 }
03727 }
03728
03729 void PlaybackBox::stopPlaylistJobQueueJob(int jobType)
03730 {
03731 ProgramInfo *tmpItem;
03732 QStringList::Iterator it;
03733 int jobID;
03734
03735 if (expectingPopup)
03736 cancelPopup();
03737
03738 for (it = playList.begin(); it != playList.end(); ++it)
03739 {
03740 jobID = 0;
03741 tmpItem = findMatchingProg(*it);
03742 if (tmpItem &&
03743 (JobQueue::IsJobQueuedOrRunning(jobType, tmpItem->chanid,
03744 tmpItem->recstartts)))
03745 {
03746 JobQueue::ChangeJobCmds(jobType, tmpItem->chanid,
03747 tmpItem->recstartts, JOB_STOP);
03748 if ((jobType & JOB_COMMFLAG) && (tmpItem))
03749 {
03750 tmpItem->programflags &= ~FL_EDITING;
03751 tmpItem->programflags &= ~FL_COMMFLAG;
03752 }
03753 }
03754 }
03755 }
03756
03757 void PlaybackBox::askDelete(void)
03758 {
03759 if (!expectingPopup)
03760 return;
03761
03762 cancelPopup();
03763
03764 showDeletePopup(delitem, DeleteRecording);
03765 }
03766
03767 void PlaybackBox::noDelete(void)
03768 {
03769 previewSuspend = false;
03770 if (!expectingPopup)
03771 return;
03772
03773 cancelPopup();
03774
03775 previewVideoState = kChanging;
03776
03777 previewVideoRefreshTimer->start(500);
03778 }
03779
03780 void PlaybackBox::doPlaylistDelete(void)
03781 {
03782 playlistDelete(false);
03783 }
03784
03785 void PlaybackBox::doPlaylistDeleteForgetHistory(void)
03786 {
03787 playlistDelete(true);
03788 }
03789
03790 void PlaybackBox::playlistDelete(bool forgetHistory)
03791 {
03792 if (!expectingPopup)
03793 return;
03794
03795 cancelPopup();
03796
03797 ProgramInfo *tmpItem;
03798 QStringList::Iterator it;
03799
03800 for (it = playList.begin(); it != playList.end(); ++it )
03801 {
03802 tmpItem = findMatchingProg(*it);
03803 if (tmpItem && (REC_CAN_BE_DELETED(tmpItem)))
03804 RemoteDeleteRecording(tmpItem, forgetHistory, false);
03805 }
03806
03807 connected = FillList();
03808 playList.clear();
03809 }
03810
03811 void PlaybackBox::doUndelete(void)
03812 {
03813 if (!expectingPopup)
03814 {
03815 previewSuspend = false;
03816 return;
03817 }
03818
03819 cancelPopup();
03820 RemoteUndeleteRecording(curitem);
03821 }
03822
03823 void PlaybackBox::doDelete(void)
03824 {
03825 if (!expectingPopup)
03826 {
03827 previewSuspend = false;
03828 return;
03829 }
03830
03831 cancelPopup();
03832
03833 if ((delitem->availableStatus == asPendingDelete) ||
03834 (!REC_CAN_BE_DELETED(delitem)))
03835 {
03836 showAvailablePopup(delitem);
03837 previewSuspend = false;
03838 return;
03839 }
03840
03841 bool result = doRemove(delitem, false, false);
03842
03843 previewVideoState = kChanging;
03844
03845 previewVideoRefreshTimer->start(500);
03846
03847 if (result)
03848 {
03849 ProgramInfo *tmpItem = findMatchingProg(delitem);
03850 if (tmpItem)
03851 tmpItem->availableStatus = asPendingDelete;
03852 previewSuspend = false;
03853 }
03854 else
03855 showDeletePopup(delitem, ForceDeleteRecording);
03856 }
03857
03858 void PlaybackBox::doForceDelete(void)
03859 {
03860 if (!expectingPopup)
03861 {
03862 previewSuspend = false;
03863 return;
03864 }
03865
03866 cancelPopup();
03867
03868 if ((delitem->availableStatus == asPendingDelete) ||
03869 (!REC_CAN_BE_DELETED(delitem)))
03870 {
03871 showAvailablePopup(delitem);
03872 previewSuspend = false;
03873 return;
03874 }
03875
03876 doRemove(delitem, true, true);
03877
03878 previewVideoState = kChanging;
03879
03880 previewVideoRefreshTimer->start(500);
03881 }
03882
03883 void PlaybackBox::doDeleteForgetHistory(void)
03884 {
03885 if (!expectingPopup)
03886 {
03887 previewSuspend = false;
03888 return;
03889 }
03890
03891 cancelPopup();
03892
03893 if ((delitem->availableStatus == asPendingDelete) ||
03894 (!REC_CAN_BE_DELETED(delitem)))
03895 {
03896 showAvailablePopup(delitem);
03897 previewSuspend = false;
03898 return;
03899 }
03900
03901 bool result = doRemove(delitem, true, false);
03902
03903 previewVideoState = kChanging;
03904
03905 previewVideoRefreshTimer->start(500);
03906
03907 if (result)
03908 {
03909 ProgramInfo *tmpItem = findMatchingProg(delitem);
03910 if (tmpItem)
03911 tmpItem->availableStatus = asPendingDelete;
03912 previewSuspend = false;
03913 }
03914 else
03915 showDeletePopup(delitem, ForceDeleteRecording);
03916 }
03917
03918 ProgramInfo *PlaybackBox::findMatchingProg(ProgramInfo *pginfo)
03919 {
03920 ProgramInfo *p;
03921 ProgramList *l = &progLists[""];
03922
03923 for (p = l->first(); p; p = l->next())
03924 {
03925 if (p->recstartts == pginfo->recstartts &&
03926 p->chanid == pginfo->chanid)
03927 return p;
03928 }
03929
03930 return NULL;
03931 }
03932
03933 ProgramInfo *PlaybackBox::findMatchingProg(QString key)
03934 {
03935 QStringList keyParts;
03936
03937 if ((key == "") || (key.find('_') < 0))
03938 return NULL;
03939
03940 keyParts = QStringList::split("_", key);
03941
03942
03943 if (keyParts.count() == 2)
03944 return findMatchingProg(keyParts[0], keyParts[1]);
03945 else
03946 return NULL;
03947 }
03948
03949 ProgramInfo *PlaybackBox::findMatchingProg(QString chanid, QString recstartts)
03950 {
03951 ProgramInfo *p;
03952 ProgramList *l = &progLists[""];
03953
03954 for (p = l->first(); p; p = l->next())
03955 {
03956 if (p->recstartts.toString(Qt::ISODate) == recstartts &&
03957 p->chanid == chanid)
03958 return p;
03959 }
03960
03961 return NULL;
03962 }
03963
03964 void PlaybackBox::setUnwatched(void)
03965 {
03966 if (!expectingPopup && delitem)
03967 return;
03968
03969 cancelPopup();
03970
03971 delitem->SetWatchedFlag(0);
03972
03973 ProgramInfo *tmpItem = findMatchingProg(delitem);
03974 if (tmpItem)
03975 tmpItem->programflags &= ~FL_WATCHED;
03976
03977 delete delitem;
03978 delitem = NULL;
03979
03980 previewVideoState = kChanging;
03981
03982 connected = FillList();
03983 update(drawListBounds);
03984 }
03985
03986 void PlaybackBox::setWatched(void)
03987 {
03988 if (!expectingPopup)
03989 return;
03990
03991 cancelPopup();
03992
03993 delitem->SetWatchedFlag(1);
03994
03995 ProgramInfo *tmpItem = findMatchingProg(delitem);
03996 if (tmpItem)
03997 tmpItem->programflags |= FL_WATCHED;
03998
03999 delete delitem;
04000 delitem = NULL;
04001
04002 previewVideoState = kChanging;
04003
04004 connected = FillList();
04005 update(drawListBounds);
04006 }
04007
04008 void PlaybackBox::toggleAutoExpire(bool turnOn)
04009 {
04010 if (!expectingPopup)
04011 return;
04012
04013 ProgramInfo *tmpItem = findMatchingProg(delitem);
04014
04015 if (tmpItem)
04016 {
04017 tmpItem->SetAutoExpire(turnOn, true);
04018
04019 if (turnOn)
04020 tmpItem->programflags |= FL_AUTOEXP;
04021 else
04022 tmpItem->programflags &= ~FL_AUTOEXP;
04023
04024 update(drawListBounds);
04025 }
04026 }
04027
04028 void PlaybackBox::togglePreserveEpisode(bool turnOn)
04029 {
04030 if (!expectingPopup)
04031 return;
04032
04033 ProgramInfo *tmpItem = findMatchingProg(delitem);
04034
04035 if (tmpItem)
04036 {
04037 if (tmpItem->availableStatus != asAvailable)
04038 showAvailablePopup(tmpItem);
04039 else
04040 tmpItem->SetPreserveEpisode(turnOn);
04041 }
04042 }
04043
04044 void PlaybackBox::PopupDone(int r)
04045 {
04046 if ((MythDialog::Rejected == r) && expectingPopup)
04047 {
04048 cancelPopup();
04049 previewVideoState = kChanging;
04050 }
04051 }
04052
04053 void PlaybackBox::toggleView(ViewMask itemMask, bool setOn)
04054 {
04055 if (setOn)
04056 viewMask = (ViewMask)(viewMask | itemMask);
04057 else
04058 viewMask = (ViewMask)(viewMask & ~itemMask);
04059
04060 connected = FillList(true);
04061 paintSkipUpdate = false;
04062 update(drawTotalBounds);
04063 }
04064
04065 void PlaybackBox::UpdateProgressBar(void)
04066 {
04067 update(drawUsageBounds);
04068 }
04069
04070 void PlaybackBox::togglePlayListTitle(void)
04071 {
04072 if (expectingPopup)
04073 cancelPopup();
04074
04075 if (!curitem)
04076 return;
04077
04078 QString currentTitle = titleList[titleIndex].lower();
04079 ProgramInfo *p;
04080
04081 for( unsigned int i = 0; i < progLists[currentTitle].count(); i++)
04082 {
04083 p = progLists[currentTitle].at(i);
04084 if (p && (p->availableStatus == asAvailable))
04085 togglePlayListItem(p);
04086 }
04087
04088 if (inTitle)
04089 cursorRight();
04090 }
04091
04092 void PlaybackBox::togglePlayListItem(void)
04093 {
04094 if (expectingPopup)
04095 cancelPopup();
04096
04097 if (!curitem)
04098 return;
04099
04100 if (curitem->availableStatus != asAvailable)
04101 {
04102 showAvailablePopup(curitem);
04103 return;
04104 }
04105
04106 togglePlayListItem(curitem);
04107
04108 if (!inTitle)
04109 cursorDown();
04110
04111 paintSkipUpdate = false;
04112 update(drawListBounds);
04113 }
04114
04115 void PlaybackBox::togglePlayListItem(ProgramInfo *pginfo)
04116 {
04117 if (!pginfo)
04118 return;
04119
04120 if (pginfo->availableStatus != asAvailable)
04121 {
04122 showAvailablePopup(pginfo);
04123 return;
04124 }
04125
04126 QString key = pginfo->MakeUniqueKey();
04127
04128 if (playList.grep(key).count())
04129 {
04130 QStringList tmpList;
04131 QStringList::Iterator it;
04132
04133 tmpList = playList;
04134 playList.clear();
04135
04136 for (it = tmpList.begin(); it != tmpList.end(); ++it )
04137 {
04138 if (*it != key)
04139 playList << *it;
04140 }
04141 }
04142 else
04143 {
04144 playList << key;
04145 }
04146
04147 paintSkipUpdate = false;
04148 update(drawListBounds);
04149 }
04150
04151 void PlaybackBox::timeout(void)
04152 {
04153 if (titleList.count() <= 1)
04154 return;
04155
04156 if (previewVideoEnabled)
04157 update(blackholeBounds);
04158 }
04159
04160 void PlaybackBox::processNetworkControlCommands(void)
04161 {
04162 int commands = 0;
04163 QString command;
04164
04165 ncLock.lock();
04166 commands = networkControlCommands.size();
04167 ncLock.unlock();
04168
04169 while (commands)
04170 {
04171 ncLock.lock();
04172 command = networkControlCommands.front();
04173 networkControlCommands.pop_front();
04174 ncLock.unlock();
04175
04176 processNetworkControlCommand(command);
04177
04178 ncLock.lock();
04179 commands = networkControlCommands.size();
04180 ncLock.unlock();
04181 }
04182 }
04183
04184 void PlaybackBox::processNetworkControlCommand(QString command)
04185 {
04186 QStringList tokens = QStringList::split(" ", command);
04187
04188 if (tokens.size() >= 4 && (tokens[1] == "PLAY" || tokens[1] == "RESUME"))
04189 {
04190 if (tokens.size() == 5 && tokens[2] == "PROGRAM")
04191 {
04192 VERBOSE(VB_IMPORTANT,
04193 QString("NetworkControl: Trying to %1 program '%2' @ '%3'")
04194 .arg(tokens[1]).arg(tokens[3]).arg(tokens[4]));
04195
04196 if (playingSomething)
04197 {
04198 VERBOSE(VB_IMPORTANT,
04199 "NetworkControl: ERROR: Already playing");
04200
04201 MythEvent me("NETWORK_CONTROL RESPONSE ERROR: Unable to play, "
04202 "player is already playing another recording.");
04203 gContext->dispatch(me);
04204 return;
04205 }
04206
04207 ProgramInfo *tmpItem =
04208 ProgramInfo::GetProgramFromRecorded(tokens[3], tokens[4]);
04209
04210 if (tmpItem)
04211 {
04212 if (curitem)
04213 delete curitem;
04214
04215 curitem = tmpItem;
04216
04217 MythEvent me("NETWORK_CONTROL RESPONSE OK");
04218 gContext->dispatch(me);
04219
04220 if (tokens[1] == "PLAY")
04221 curitem->setIgnoreBookmark(true);
04222
04223 underNetworkControl = true;
04224 playSelected();
04225 underNetworkControl = false;
04226 }
04227 else
04228 {
04229 QString message = QString("NETWORK_CONTROL RESPONSE "
04230 "ERROR: Could not find recording for "
04231 "chanid %1 @ %2")
04232 .arg(tokens[3]).arg(tokens[4]);
04233 MythEvent me(message);
04234 gContext->dispatch(me);
04235 }
04236 }
04237 }
04238 }
04239
04240 void PlaybackBox::keyPressEvent(QKeyEvent *e)
04241 {
04242 bool handled = false;
04243
04244 if (ignoreKeyPressEvents)
04245 return;
04246
04247
04248 if ((e->key() == Qt::Key_LaunchMedia) &&
04249 (e->state() == (Qt::MouseButtonMask | Qt::KeyButtonMask)))
04250 {
04251 e->accept();
04252 ncLock.lock();
04253 int commands = networkControlCommands.size();
04254 ncLock.unlock();
04255 if (commands)
04256 processNetworkControlCommands();
04257 return;
04258 }
04259
04260 QStringList actions;
04261 gContext->GetMainWindow()->TranslateKeyPress("TV Frontend", e, actions);
04262
04263 for (unsigned int i = 0; i < actions.size() && !handled; i++)
04264 {
04265 QString action = actions[i];
04266 handled = true;
04267
04268 if (action == "ESCAPE")
04269 exitWin();
04270 else if (action == "1" || action == "HELP")
04271 showIconHelp();
04272 else if (action == "MENU")
04273 showMenu();
04274 else if (action == "NEXTFAV")
04275 {
04276 if (inTitle)
04277 togglePlayListTitle();
04278 else
04279 togglePlayListItem();
04280 }
04281 else if (action == "TOGGLEFAV")
04282 {
04283 playList.clear();
04284 connected = FillList(true);
04285 paintSkipUpdate = false;
04286 update(drawTotalBounds);
04287 }
04288 else if (action == "TOGGLERECORD")
04289 {
04290 viewMask = viewMaskToggle(viewMask, VIEW_TITLES);
04291 connected = FillList(true);
04292 paintSkipUpdate = false;
04293 update(drawTotalBounds);
04294 }
04295 else if (action == "CHANGERECGROUP")
04296 showRecGroupChooser();
04297 else if (action == "CHANGEGROUPVIEW")
04298 showViewChanger();
04299 else if (titleList.count() > 1)
04300 {
04301 if (action == "DELETE")
04302 deleteSelected();
04303 else if (action == "PLAYBACK")
04304 playSelected();
04305 else if (action == "INFO")
04306 showActionsSelected();
04307 else if (action == "DETAILS")
04308 details();
04309 else if (action == "CUSTOMEDIT")
04310 customEdit();
04311 else if (action == "UPCOMING")
04312 upcoming();
04313 else if (action == "SELECT")
04314 selected();
04315 else if (action == "UP")
04316 cursorUp();
04317 else if (action == "DOWN")
04318 cursorDown();
04319 else if (action == "LEFT")
04320 cursorLeft();
04321 else if (action == "RIGHT")
04322 cursorRight();
04323 else if (action == "PAGEUP")
04324 pageUp();
04325 else if (action == "PAGEDOWN")
04326 pageDown();
04327 else if (action == "PAGETOP")
04328 pageTop();
04329 else if (action == "PAGEMIDDLE")
04330 pageMiddle();
04331 else if (action == "PAGEBOTTOM")
04332 pageBottom();
04333 else if (action == "PREVVIEW")
04334 cursorUp(false, true);
04335 else if (action == "NEXTVIEW")
04336 cursorDown(false, true);
04337 else
04338 handled = false;
04339 }
04340 else
04341 {
04342 if (action == "LEFT" && arrowAccel)
04343 exitWin();
04344 else
04345 handled = false;
04346 }
04347 }
04348
04349 if (!handled)
04350 MythDialog::keyPressEvent(e);
04351 }
04352
04353 void PlaybackBox::customEvent(QCustomEvent *e)
04354 {
04355 if ((MythEvent::Type)(e->type()) == MythEvent::MythEventMessage)
04356 {
04357 MythEvent *me = (MythEvent *)e;
04358 QString message = me->Message();
04359
04360 if (message.left(21) == "RECORDING_LIST_CHANGE")
04361 {
04362 QStringList tokens = QStringList::split(" ", message);
04363 if (tokens.size() == 1)
04364 {
04365 fillListFromCache = false;
04366 if (!fillListTimer->isActive())
04367 fillListTimer->start(1000, true);
04368 }
04369 else if ((tokens[1] == "DELETE") && (tokens.size() == 4))
04370 {
04371 progCacheLock.lock();
04372 if (!progCache)
04373 {
04374 progCacheLock.unlock();
04375 freeSpaceNeedsUpdate = true;
04376 fillListFromCache = false;
04377 fillListTimer->start(1000, true);
04378 return;
04379 }
04380 vector<ProgramInfo *>::iterator i = progCache->begin();
04381 for ( ; i != progCache->end(); i++)
04382 {
04383 if (((*i)->chanid == tokens[2]) &&
04384 ((*i)->recstartts.toString(Qt::ISODate) == tokens[3]))
04385 {
04386 (*i)->availableStatus = asDeleted;
04387 break;
04388 }
04389 }
04390
04391 progCacheLock.unlock();
04392 freeSpaceNeedsUpdate = true;
04393 if (!fillListTimer->isActive())
04394 {
04395 fillListFromCache = true;
04396 fillListTimer->start(1000, true);
04397 }
04398 }
04399 }
04400 else if (message.left(15) == "NETWORK_CONTROL")
04401 {
04402 QStringList tokens = QStringList::split(" ", message);
04403 if ((tokens[1] != "ANSWER") && (tokens[1] != "RESPONSE"))
04404 {
04405 ncLock.lock();
04406 networkControlCommands.push_back(message);
04407 ncLock.unlock();
04408
04409
04410 QKeyEvent *event;
04411 int buttons =
04412 (Qt::MouseButtonMask | Qt::KeyButtonMask);
04413
04414 event = new QKeyEvent(QEvent::KeyPress, Qt::Key_LaunchMedia,
04415 0, buttons);
04416 QApplication::postEvent((QObject*)(gContext->GetMainWindow()),
04417 event);
04418
04419 event = new QKeyEvent(QEvent::KeyRelease, Qt::Key_LaunchMedia,
04420 0, buttons);
04421 QApplication::postEvent((QObject*)(gContext->GetMainWindow()),
04422 event);
04423 }
04424 }
04425 }
04426 }
04427
04428 bool PlaybackBox::fileExists(ProgramInfo *pginfo)
04429 {
04430 if (pginfo)
04431 return pginfo->PathnameExists();
04432 return false;
04433 }
04434
04435 QDateTime PlaybackBox::getPreviewLastModified(ProgramInfo *pginfo)
04436 {
04437 QDateTime datetime;
04438 QString filename = pginfo->pathname + ".png";
04439
04440 if (filename.left(7) != "myth://")
04441 {
04442 QFileInfo retfinfo(filename);
04443 if (retfinfo.exists())
04444 datetime = retfinfo.lastModified();
04445 }
04446 else
04447 {
04448 datetime = RemoteGetPreviewLastModified(pginfo);
04449 }
04450
04451 return datetime;
04452 }
04453
04454 void PlaybackBox::IncPreviewGeneratorPriority(const QString &xfn)
04455 {
04456 QString fn = QDeepCopy<QString>(xfn.mid(max(xfn.findRev('/') + 1,0)));
04457
04458 QMutexLocker locker(&previewGeneratorLock);
04459 vector<QString> &q = previewGeneratorQueue;
04460 vector<QString>::iterator it = std::find(q.begin(), q.end(), fn);
04461 if (it != q.end())
04462 q.erase(it);
04463
04464 PreviewMap::iterator pit = previewGenerator.find(fn);
04465 if (pit != previewGenerator.end() && (*pit).gen && !(*pit).genStarted)
04466 q.push_back(fn);
04467 }
04468
04469 void PlaybackBox::UpdatePreviewGeneratorThreads(void)
04470 {
04471 QMutexLocker locker(&previewGeneratorLock);
04472 vector<QString> &q = previewGeneratorQueue;
04473 if ((previewGeneratorRunning < previewGeneratorMaxRunning) && q.size())
04474 {
04475 QString fn = q.back();
04476 q.pop_back();
04477 PreviewMap::iterator it = previewGenerator.find(fn);
04478 if (it != previewGenerator.end() && (*it).gen && !(*it).genStarted)
04479 {
04480 previewGeneratorRunning++;
04481 (*it).gen->Start();
04482 (*it).genStarted = true;
04483 }
04484 }
04485 }
04486
04491 bool PlaybackBox::SetPreviewGenerator(const QString &xfn, PreviewGenerator *g)
04492 {
04493 QString fn = QDeepCopy<QString>(xfn.mid(max(xfn.findRev('/') + 1,0)));
04494 QMutexLocker locker(&previewGeneratorLock);
04495
04496 if (!g)
04497 {
04498 previewGeneratorRunning = max(0, (int)previewGeneratorRunning - 1);
04499 PreviewMap::iterator it = previewGenerator.find(fn);
04500 if (it == previewGenerator.end())
04501 return false;
04502
04503 (*it).gen = NULL;
04504 (*it).genStarted = false;
04505 (*it).ready = false;
04506 (*it).lastBlockTime =
04507 max(PreviewGenState::minBlockSeconds, (*it).lastBlockTime * 2);
04508 (*it).blockRetryUntil =
04509 QDateTime::currentDateTime().addSecs((*it).lastBlockTime);
04510
04511 return true;
04512 }
04513
04514 g->AttachSignals(this);
04515 previewGenerator[fn].gen = g;
04516 previewGenerator[fn].genStarted = false;
04517 previewGenerator[fn].ready = false;
04518
04519 previewGeneratorLock.unlock();
04520 IncPreviewGeneratorPriority(xfn);
04521 previewGeneratorLock.lock();
04522
04523 return true;
04524 }
04525
04530 bool PlaybackBox::IsGeneratingPreview(const QString &xfn, bool really) const
04531 {
04532 PreviewMap::const_iterator it;
04533 QMutexLocker locker(&previewGeneratorLock);
04534
04535 QString fn = xfn.mid(max(xfn.findRev('/') + 1,0));
04536 if ((it = previewGenerator.find(fn)) == previewGenerator.end())
04537 return false;
04538
04539 if (really)
04540 return ((*it).gen && !(*it).ready);
04541
04542 if ((*it).blockRetryUntil.isValid())
04543 return QDateTime::currentDateTime() < (*it).blockRetryUntil;
04544
04545 return (*it).gen;
04546 }
04547
04552 uint PlaybackBox::IncPreviewGeneratorAttempts(const QString &xfn)
04553 {
04554 QMutexLocker locker(&previewGeneratorLock);
04555 QString fn = xfn.mid(max(xfn.findRev('/') + 1,0));
04556 return previewGenerator[fn].attempts++;
04557 }
04558
04559 void PlaybackBox::previewThreadDone(const QString &fn, bool &success)
04560 {
04561 success = SetPreviewGenerator(fn, NULL);
04562 UpdatePreviewGeneratorThreads();
04563 }
04564
04570 void PlaybackBox::previewReady(const ProgramInfo *pginfo)
04571 {
04572 QString xfn = pginfo->pathname + ".png";
04573 QString fn = xfn.mid(max(xfn.findRev('/') + 1,0));
04574
04575 previewGeneratorLock.lock();
04576 PreviewMap::iterator it = previewGenerator.find(fn);
04577 if (it != previewGenerator.end())
04578 {
04579 (*it).ready = true;
04580 (*it).attempts = 0;
04581 (*it).lastBlockTime = 0;
04582 }
04583 previewGeneratorLock.unlock();
04584
04585
04586
04587 qApp->lock();
04588
04589
04590 if (pginfo->recstartts == previewStartts &&
04591 pginfo->chanid == previewChanid &&
04592 previewLastModified == previewFilets &&
04593 titleList.count() > 1)
04594 {
04595 if (previewPixmap)
04596 {
04597 delete previewPixmap;
04598 previewPixmap = NULL;
04599 }
04600
04601
04602 update(blackholeBounds);
04603 }
04604 qApp->unlock();
04605 }
04606
04607 bool check_lastmod(LastCheckedMap &elapsedtime, const QString &filename)
04608 {
04609 LastCheckedMap::iterator it = elapsedtime.find(filename);
04610
04611 if (it != elapsedtime.end() && ((*it).elapsed() < 250))
04612 return false;
04613
04614 elapsedtime[filename].restart();
04615 return true;
04616 }
04617
04618 static QSize calc_preview_size(const QSize &bounds, const QSize &imageSize)
04619 {
04620 if ((bounds.width() == imageSize.width()) &&
04621 (imageSize.height() <= bounds.height()))
04622 {
04623 return imageSize;
04624 }
04625
04626 float boundsaspect = 4.0f / 3.0f;
04627 float imageaspect = 4.0f / 3.0f;
04628 QSize previewSize = bounds;
04629
04630 if ((bounds.width() > 0) && (bounds.height() > 0))
04631 boundsaspect = ((float)bounds.width()) / ((float)bounds.height());
04632
04633 if ((imageSize.width() > 0) && (imageSize.height() > 0))
04634 imageaspect = ((float)imageSize.width()) / ((float)imageSize.height());
04635
04636
04637 if ((int)((boundsaspect + 0.05f) * 10) >
04638 (int)((imageaspect + 0.05f) * 10))
04639 {
04640 float scaleratio = imageaspect / boundsaspect;
04641 previewSize.setWidth((int)(previewSize.width() * scaleratio));
04642 }
04643 else if ((int)((boundsaspect + 0.05f) * 10) <
04644 (int)((imageaspect + 0.05f) * 10))
04645 {
04646 float scaleratio = boundsaspect / imageaspect;
04647 previewSize.setHeight((int)(previewSize.height() * scaleratio));
04648 }
04649
04650
04651
04652
04653
04654
04655 return previewSize;
04656 }
04657
04658 QPixmap PlaybackBox::getPixmap(ProgramInfo *pginfo)
04659 {
04660 QPixmap retpixmap;
04661
04662 if (!previewPixmapEnabled || !pginfo)
04663 return retpixmap;
04664
04665 if ((asPendingDelete == pginfo->availableStatus) || previewSuspend)
04666 {
04667 if (previewPixmap)
04668 retpixmap = *previewPixmap;
04669
04670 return retpixmap;
04671 }
04672
04673 QString filename = pginfo->pathname + ".png";
04674 bool check_date = check_lastmod(previewLastModifyCheck, filename);
04675
04676 if (check_date)
04677 previewLastModified = getPreviewLastModified(pginfo);
04678
04679 IncPreviewGeneratorPriority(filename);
04680
04681 if (previewFromBookmark &&
04682 check_date &&
04683 (!previewLastModified.isValid() ||
04684 (previewLastModified < pginfo->lastmodified &&
04685 previewLastModified >= pginfo->recendts)) &&
04686 !pginfo->IsEditing() &&
04687 !JobQueue::IsJobRunning(JOB_COMMFLAG, pginfo) &&
04688 !IsGeneratingPreview(filename))
04689 {
04690 VERBOSE(VB_PLAYBACK, QString("Starting preview generator ") +
04691 QString("%1 && (%2 || ((%3<%4)->%5 && (%6>=%7)->%8)) && ")
04692 .arg(previewFromBookmark)
04693 .arg(!previewLastModified.isValid())
04694 .arg(previewLastModified.toString(Qt::ISODate))
04695 .arg(pginfo->lastmodified.toString(Qt::ISODate))
04696 .arg(previewLastModified < pginfo->lastmodified)
04697 .arg(previewLastModified.toString(Qt::ISODate))
04698 .arg(pginfo->recendts.toString(Qt::ISODate))
04699 .arg(previewLastModified >= pginfo->recendts) +
04700 QString("%1 && %2 && %3")
04701 .arg(!pginfo->IsEditing())
04702 .arg(!JobQueue::IsJobRunning(JOB_COMMFLAG, pginfo))
04703 .arg(!IsGeneratingPreview(filename)));
04704
04705 uint attempts = IncPreviewGeneratorAttempts(filename);
04706 if (attempts < PreviewGenState::maxAttempts)
04707 {
04708 SetPreviewGenerator(filename, new PreviewGenerator(pginfo, false));
04709 }
04710 else if (attempts == PreviewGenState::maxAttempts)
04711 {
04712 VERBOSE(VB_IMPORTANT, LOC_ERR +
04713 QString("Attempted to generate preview for '%1' "
04714 "%2 times, giving up.")
04715 .arg(filename).arg(PreviewGenState::maxAttempts));
04716 }
04717
04718 if (attempts >= PreviewGenState::maxAttempts)
04719 return retpixmap;
04720 }
04721
04722 UpdatePreviewGeneratorThreads();
04723
04724
04725 if (previewPixmap &&
04726 pginfo->recstartts == previewStartts &&
04727 pginfo->chanid == previewChanid &&
04728 previewLastModified == previewFilets)
04729 {
04730 return *previewPixmap;
04731 }
04732
04733 paintSkipUpdate = false;
04734
04735 if (previewPixmap)
04736 {
04737 delete previewPixmap;
04738 previewPixmap = NULL;
04739 }
04740
04741 int screenheight = 0, screenwidth = 0;
04742 float wmult = 0, hmult = 0;
04743
04744 gContext->GetScreenSettings(screenwidth, wmult, screenheight, hmult);
04745
04746 previewPixmap = gContext->LoadScalePixmap(filename, true );
04747 if (previewPixmap)
04748 {
04749 previewStartts = pginfo->recstartts;
04750 previewChanid = pginfo->chanid;
04751 previewFilets = previewLastModified;
04752 QSize previewSize = calc_preview_size(
04753 blackholeBounds.size(), previewPixmap->size());
04754 if (previewSize != previewPixmap->size())
04755 previewPixmap->resize(previewSize);
04756 retpixmap = *previewPixmap;
04757 return retpixmap;
04758 }
04759
04760
04761
04762 bool refreshPixmap = (previewLastModified >= previewFilets);
04763
04764 QImage *image = NULL;
04765 if (!IsGeneratingPreview(filename, true))
04766 image = gContext->CacheRemotePixmap(filename, refreshPixmap);
04767
04768
04769 if (!image && !IsGeneratingPreview(filename))
04770 {
04771 uint attempts = IncPreviewGeneratorAttempts(filename);
04772 if (attempts < PreviewGenState::maxAttempts)
04773 {
04774 VERBOSE(VB_PLAYBACK, "Starting preview generator");
04775 SetPreviewGenerator(filename, new PreviewGenerator(pginfo, false));
04776 }
04777 else if (attempts == PreviewGenState::maxAttempts)
04778 {
04779 VERBOSE(VB_IMPORTANT, LOC_ERR +
04780 QString("Attempted to generate preview for '%1' "
04781 "%2 times, giving up.")
04782 .arg(filename).arg(PreviewGenState::maxAttempts));
04783
04784 return retpixmap;
04785 }
04786 }
04787
04788 if (image)
04789 {
04790 previewPixmap = new QPixmap();
04791
04792 QSize previewSize = calc_preview_size(
04793 blackholeBounds.size(), image->size());
04794
04795 if (previewSize == previewPixmap->size())
04796 previewPixmap->convertFromImage(*image);
04797 else
04798 {
04799 QImage tmp2 = image->smoothScale(previewSize);
04800 previewPixmap->convertFromImage(tmp2);
04801 }
04802 }
04803
04804 if (!previewPixmap)
04805 {
04806 previewPixmap = new QPixmap((int)(blackholeBounds.width()),
04807 (int)(blackholeBounds.height()));
04808 previewPixmap->fill(black);
04809 }
04810
04811 retpixmap = *previewPixmap;
04812 previewStartts = pginfo->recstartts;
04813 previewChanid = pginfo->chanid;
04814 previewFilets = previewLastModified;
04815
04816 return retpixmap;
04817 }
04818
04819 void PlaybackBox::showIconHelp(void)
04820 {
04821 if (expectingPopup)
04822 cancelPopup();
04823
04824 int curRow = 1;
04825 int curCol = 0;
04826 LayerSet *container = NULL;
04827 if (type != Delete)
04828 container = theme->GetSet("program_info_play");
04829 else
04830 container = theme->GetSet("program_info_del");
04831
04832 if (!container)
04833 return;
04834
04835 MythPopupBox *iconhelp = new MythPopupBox(
04836 gContext->GetMainWindow(), true, drawPopupFgColor,
04837 drawPopupBgColor, drawPopupSelColor, "icon help");
04838
04839 QGridLayout *grid = new QGridLayout(6, 4, (int)(5 * wmult));
04840
04841 QLabel *label;
04842 UIImageType *itype;
04843 bool displayme = false;
04844
04845 label = new QLabel(tr("Status Icons"), iconhelp, "");
04846 QFont font = label->font();
04847 font.setPointSize(int (font.pointSize() * 1.5));
04848 font.setBold(true);
04849 label->setFont(font);
04850 label->setBackgroundOrigin(ParentOrigin);
04851 label->setPaletteForegroundColor(drawPopupFgColor);
04852 label->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
04853 label->setMinimumWidth((int)(600 * wmult));
04854 label->setMaximumWidth((int)(600 * wmult));
04855 label->setMinimumHeight((int)(35 * hmult));
04856 label->setMaximumHeight((int)(35 * hmult));
04857 grid->addMultiCellWidget(label, 0, 0, 0, 3, Qt::AlignHCenter);
04858
04859 QMap <QString, QString>::iterator it;
04860 QMap <QString, QString> iconMap;
04861 iconMap["commflagged"] = tr("Commercials are flagged");
04862 iconMap["cutlist"] = tr("An editing cutlist is present");
04863 iconMap["autoexpire"] = tr("The program is able to auto-expire");
04864 iconMap["processing"] = tr("Commercials are being flagged");
04865 iconMap["bookmark"] = tr("A bookmark is set");
04866 iconMap["inuse"] = tr("Recording is in use");
04867 iconMap["transcoded"] = tr("Recording has been transcoded");
04868
04869 iconMap["mono"] = tr("Recording is in Mono");
04870 iconMap["stereo"] = tr("Recording is in Stereo");
04871 iconMap["surround"] = tr("Recording is in Surround Sound");
04872 iconMap["dolby"] = tr("Recording is in Dolby Surround Sound");
04873
04874 iconMap["cc"] = tr("Recording is Closed Captioned");
04875 iconMap["subtitles"] = tr("Recording has Subtitles Available");
04876 iconMap["onscreensub"] = tr("Recording is Subtitled");
04877
04878 iconMap["hdtv"] = tr("Recording is in High Definition");
04879 iconMap["widescreen"] = tr("Recording is in WideScreen");
04880
04881 iconMap["watched"] = tr("Recording has been watched");
04882 iconMap["preserved"] = tr("Recording is preserved");
04883
04884 for (it = iconMap.begin(); it != iconMap.end(); ++it)
04885 {
04886 itype = (UIImageType *)container->GetType(it.key());
04887 if (itype)
04888 {
04889 if (curCol == 0)
04890 label = new QLabel(it.data(), iconhelp, "nopopsize");
04891 else
04892 label = new QLabel(it.data(), iconhelp, "");
04893 label->setAlignment(Qt::WordBreak | Qt::AlignLeft | Qt::AlignVCenter);
04894 label->setBackgroundOrigin(ParentOrigin);
04895 label->setPaletteForegroundColor(drawPopupFgColor);
04896 label->setMinimumHeight((int)(50 * hmult));
04897 label->setMaximumHeight((int)(50 * hmult));
04898
04899 grid->addWidget(label, curRow, curCol + 1, Qt::AlignLeft);
04900
04901 label = new QLabel(iconhelp, "nopopsize");
04902
04903 itype->ResetFilename();
04904 itype->LoadImage();
04905 label->setPixmap(itype->GetImage());
04906 displayme = true;
04907
04908 label->setBackgroundOrigin(ParentOrigin);
04909 label->setPaletteForegroundColor(drawPopupFgColor);
04910 grid->addWidget(label, curRow, curCol, Qt::AlignCenter);
04911
04912 curCol += 2;
04913 curCol %= 4;
04914 if (curCol == 0)
04915 curRow++;
04916 }
04917 }
04918
04919 if (!displayme)
04920 {
04921 iconhelp->hide();
04922 iconhelp->deleteLater();
04923 return;
04924 }
04925
04926 killPlayerSafe();
04927
04928 iconhelp->addLayout(grid);
04929
04930 QButton *button = iconhelp->addButton(
04931 QObject::tr("OK"), iconhelp, SLOT(accept()));
04932 button->setFocus();
04933
04934 iconhelp->ExecPopup();
04935
04936 iconhelp->hide();
04937 iconhelp->deleteLater();
04938
04939 previewVideoState = kChanging;
04940
04941 paintSkipUpdate = false;
04942 paintSkipCount = 2;
04943
04944 setActiveWindow();
04945 }
04946
04947 void PlaybackBox::initRecGroupPopup(QString title, QString name)
04948 {
04949 if (recGroupPopup)
04950 closeRecGroupPopup();
04951
04952 recGroupPopup = new MythPopupBox(gContext->GetMainWindow(), true,
04953 drawPopupFgColor, drawPopupBgColor,
04954 drawPopupSelColor, name);
04955
04956 QLabel *label = recGroupPopup->addLabel(title, MythPopupBox::Large, false);
04957 label->setAlignment(Qt::AlignCenter);
04958
04959 killPlayerSafe();
04960
04961 }
04962
04963 void PlaybackBox::closeRecGroupPopup(bool refreshList)
04964 {
04965 if (!recGroupPopup)
04966 return;
04967
04968 recGroupPopup->hide();
04969 recGroupPopup->deleteLater();
04970
04971 recGroupPopup = NULL;
04972 recGroupLineEdit = NULL;
04973 recGroupListBox = NULL;
04974 recGroupOldPassword = NULL;
04975 recGroupNewPassword = NULL;
04976 recGroupOkButton = NULL;
04977
04978 if (refreshList)
04979 connected = FillList(true);
04980
04981 paintSkipUpdate = false;
04982 paintSkipCount = 2;
04983
04984 previewVideoState = kChanging;
04985
04986 setActiveWindow();
04987
04988 EmbedTVWindow();
04989
04990 if (delitem)
04991 {
04992 delete delitem;
04993 delitem = NULL;
04994 }
04995 }
04996
04997 void PlaybackBox::showViewChanger(void)
04998 {
04999 ViewMask savedMask = viewMask;
05000
05001 if (!expectingPopup)
05002 return;
05003
05004 cancelPopup();
05005
05006 initRecGroupPopup(tr("Group View"), "showViewChanger");
05007
05008 MythCheckBox *checkBox;
05009
05010 checkBox = new MythCheckBox(tr("Show Titles"), recGroupPopup);
05011 checkBox->setChecked(viewMask & VIEW_TITLES);
05012 connect(checkBox, SIGNAL(toggled(bool)), this, SLOT(toggleTitleView(bool)));
05013 recGroupPopup->addWidget(checkBox, false);
05014 checkBox->setFocus();
05015
05016 checkBox = new MythCheckBox(tr("Show Categories"), recGroupPopup);
05017 checkBox->setChecked(viewMask & VIEW_CATEGORIES);
05018 connect(checkBox, SIGNAL(toggled(bool)), this,
05019 SLOT(toggleCategoryView(bool)));
05020 recGroupPopup->addWidget(checkBox, false);
05021
05022 checkBox = new MythCheckBox(tr("Show Recording Groups"), recGroupPopup);
05023 checkBox->setChecked(viewMask & VIEW_RECGROUPS);
05024 connect(checkBox, SIGNAL(toggled(bool)), this,
05025 SLOT(toggleRecGroupView(bool)));
05026 recGroupPopup->addWidget(checkBox, false);
05027
05028 checkBox = new MythCheckBox(tr("Show Watch List"), recGroupPopup);
05029 checkBox->setChecked(viewMask & VIEW_WATCHLIST);
05030 connect(checkBox, SIGNAL(toggled(bool)), this,
05031 SLOT(toggleWatchListView(bool)));
05032 recGroupPopup->addWidget(checkBox, false);
05033
05034 checkBox = new MythCheckBox(tr("Show Searches"), recGroupPopup);
05035 checkBox->setChecked(viewMask & VIEW_SEARCHES);
05036 connect(checkBox, SIGNAL(toggled(bool)), this,
05037 SLOT(toggleSearchView(bool)));
05038 recGroupPopup->addWidget(checkBox, false);
05039
05040 if ((recGroup == "All Programs") &&
05041 (gContext->GetNumSetting("LiveTVInAllPrograms",0)))
05042 {
05043 checkBox = new MythCheckBox(tr("Show LiveTV as a Group"),
05044 recGroupPopup);
05045 checkBox->setChecked(viewMask & VIEW_LIVETVGRP);
05046 connect(checkBox, SIGNAL(toggled(bool)), this,
05047 SLOT(toggleLiveTVView(bool)));
05048 recGroupPopup->addWidget(checkBox, false);
05049 }
05050
05051 MythPushButton *okbutton = new MythPushButton(recGroupPopup);
05052 okbutton->setText(tr("Save Current View"));
05053 recGroupPopup->addWidget(okbutton);
05054 connect(okbutton, SIGNAL(clicked()), recGroupPopup, SLOT(accept()));
05055
05056 MythPushButton *exitbutton = new MythPushButton(recGroupPopup);
05057 exitbutton->setText(tr("Cancel"));
05058 recGroupPopup->addWidget(exitbutton);
05059 connect(exitbutton, SIGNAL(clicked()), recGroupPopup, SLOT(reject()));
05060
05061 DialogCode result = recGroupPopup->ExecPopup();
05062
05063 if (result != MythDialog::Rejected)
05064 {
05065 if (viewMask == VIEW_NONE)
05066 viewMask = VIEW_TITLES;
05067 connected = FillList(true);
05068 gContext->SaveSetting("DisplayGroupDefaultViewMask", (int)viewMask);
05069 gContext->SaveSetting("PlaybackWatchList",
05070 (bool)(viewMask & VIEW_WATCHLIST));
05071 }
05072 else
05073 {
05074 viewMask = savedMask;
05075 connected = FillList(true);
05076 paintSkipUpdate = false;
05077 update(drawTotalBounds);
05078 }
05079
05080 closeRecGroupPopup(result != MythDialog::Rejected);
05081 }
05082
05083 void PlaybackBox::showRecGroupChooser(void)
05084 {
05085
05086
05087
05088 if (expectingPopup)
05089 cancelPopup();
05090
05091 initRecGroupPopup(tr("Select Group Filter"), "showRecGroupChooser");
05092
05093 QStringList groups;
05094
05095 MSqlQuery query(MSqlQuery::InitCon());
05096 QString itemStr;
05097 QString dispGroup;
05098 QString saveRecGroup = recGroup;
05099 int items;
05100 int totalItems = 0;
05101 bool liveTVInAll = gContext->GetNumSetting("LiveTVInAllPrograms",0);
05102
05103 recGroupType.clear();
05104
05105 recGroupListBox = new MythListBox(recGroupPopup);
05106
05107
05108 query.prepare(
05109 "SELECT recgroup, COUNT(title) "
05110 "FROM recorded "
05111 "WHERE deletepending = 0 "
05112 "GROUP BY recgroup");
05113 if (query.exec() && query.isActive() && query.size() > 0)
05114 {
05115 while (query.next())
05116 {
05117 dispGroup = QString::fromUtf8(query.value(0).toString());
05118 items = query.value(1).toInt();
05119 itemStr = (items == 1) ? tr("item") : tr("items");
05120
05121 if ((dispGroup != "LiveTV" || liveTVInAll) &&
05122 (dispGroup != "Deleted"))
05123 totalItems += items;
05124
05125 dispGroup = (dispGroup == "Default") ? tr("Default") : dispGroup;
05126 dispGroup = (dispGroup == "Deleted") ? tr("Deleted") : dispGroup;
05127 dispGroup = (dispGroup == "LiveTV") ? tr("LiveTV") : dispGroup;
05128
05129 groups += QString("%1 [%2 %3]").arg(dispGroup)
05130 .arg(items).arg(itemStr);
05131
05132 recGroupType[query.value(0).toString()] = "recgroup";
05133 }
05134 }
05135
05136
05137 itemStr = (totalItems == 1) ? tr("item") : tr("items");
05138 recGroupListBox->insertItem(QString("%1 [%2 %3]").arg(tr("All Programs"))
05139 .arg(totalItems).arg(itemStr));
05140 recGroupType["All Programs"] = "recgroup";
05141
05142
05143 recGroupListBox->insertItem(QString("------- %1 -------")
05144 .arg(tr("Groups")));
05145 groups.sort();
05146 recGroupListBox->insertStringList(groups);
05147 groups.clear();
05148
05149
05150 query.prepare(
05151 "SELECT DISTINCT category, COUNT(title) "
05152 "FROM recorded "
05153 "WHERE deletepending = 0 "
05154 "GROUP BY category");
05155 if (query.exec() && query.isActive() && query.size() > 0)
05156 {
05157 int unknownCount = 0;
05158 while (query.next())
05159 {
05160 items = query.value(1).toInt();
05161 itemStr = (items == 1) ? tr("item") : tr("items");
05162
05163 dispGroup = QString::fromUtf8(query.value(0).toString());
05164 if (dispGroup == "")
05165 {
05166 unknownCount += items;
05167 dispGroup = tr("Unknown");
05168 }
05169 else if (dispGroup == tr("Unknown"))
05170 unknownCount += items;
05171
05172 if ((!recGroupType.contains(dispGroup)) &&
05173 (dispGroup != tr("Unknown")))
05174 {
05175 groups += QString("%1 [%2 %3]").arg(dispGroup)
05176 .arg(items).arg(itemStr);
05177
05178 recGroupType[dispGroup] = "category";
05179 }
05180 }
05181
05182 if (unknownCount)
05183 {
05184 dispGroup = tr("Unknown");
05185 items = unknownCount;
05186 itemStr = (items == 1) ? tr("item") : tr("items");
05187 groups += QString("%1 [%2 %3]").arg(dispGroup)
05188 .arg(items).arg(itemStr);
05189
05190 recGroupType[dispGroup] = "category";
05191 }
05192 }
05193
05194
05195 recGroupListBox->insertItem(QString("------- %1 -------")
05196 .arg(tr("Categories")));
05197 groups.sort();
05198 recGroupListBox->insertStringList(groups);
05199
05200
05201 recGroupPopup->addWidget(recGroupListBox);
05202 recGroupListBox->setFocus();
05203
05204
05205 if (recGroup == "All Programs")
05206 dispGroup = tr("All Programs");
05207 else if (recGroup == "Default")
05208 dispGroup = tr("Default");
05209 else if (recGroup == "LiveTV")
05210 dispGroup = tr("LiveTV");
05211 else if (recGroup == "Deleted")
05212 dispGroup = tr("Deleted");
05213 else
05214 dispGroup = recGroup;
05215
05216
05217 int index = recGroupListBox->index(recGroupListBox->findItem(dispGroup));
05218 if (index < 0)
05219 index = 0;
05220
05221
05222 recGroupListBox->setCurrentItem((index + 1) % 2);
05223 recGroupListBox->setCurrentItem(index);
05224
05225 recGroupLastItem = recGroupListBox->currentItem();
05226
05227 connect(recGroupListBox, SIGNAL(accepted(int)),
05228 recGroupPopup, SLOT(AcceptItem(int)));
05229 connect(recGroupListBox, SIGNAL(currentChanged(QListBoxItem *)), this,
05230 SLOT(recGroupChooserListBoxChanged()));
05231
05232 DialogCode result = recGroupPopup->ExecPopup();
05233
05234 if (result != MythDialog::Rejected)
05235 setGroupFilter();
05236
05237 closeRecGroupPopup(result != MythDialog::Rejected);
05238
05239 if (result != MythDialog::Rejected)
05240 {
05241 progIndex = 0;
05242 titleIndex = 0;
05243 }
05244 }
05245
05246 void PlaybackBox::recGroupChooserListBoxChanged(void)
05247 {
05248 if (!recGroupListBox)
05249 return;
05250
05251 QString item = recGroupListBox->currentText().section(" [", 0, 0);
05252
05253 if (item.left(5) == "-----")
05254 {
05255 int thisItem = recGroupListBox->currentItem();
05256 if ((recGroupLastItem > thisItem) &&
05257 (thisItem > 0))
05258 recGroupListBox->setCurrentItem(thisItem - 1);
05259 else if ((thisItem > recGroupLastItem) &&
05260 ((unsigned int)thisItem < (recGroupListBox->count() - 1)))
05261 recGroupListBox->setCurrentItem(thisItem + 1);
05262 }
05263 recGroupLastItem = recGroupListBox->currentItem();
05264 }
05265
05266 void PlaybackBox::setGroupFilter(void)
05267 {
05268 QString savedPW = recGroupPassword;
05269 QString savedRecGroup = recGroup;
05270
05271 recGroup = recGroupListBox->currentText().section(" [", 0, 0);
05272
05273 if (recGroup == tr("Default"))
05274 recGroup = "Default";
05275 else if (recGroup == tr("All Programs"))
05276 recGroup = "All Programs";
05277 else if (recGroup == tr("LiveTV"))
05278 recGroup = "LiveTV";
05279 else if (recGroup == tr("Deleted"))
05280 recGroup = "Deleted";
05281
05282 recGroupPassword = getRecGroupPassword(recGroup);
05283
05284 if (recGroupPassword != "" )
05285 {
05286
05287 bool ok = false;
05288 QString text = tr("Password:");
05289
05290 MythPasswordDialog *pwd = new MythPasswordDialog(text, &ok,
05291 recGroupPassword,
05292 gContext->GetMainWindow());
05293 pwd->exec();
05294 pwd->deleteLater();
05295 if (!ok)
05296 {
05297 recGroupPassword = savedPW;
05298 recGroup = savedRecGroup;
05299 return;
05300 }
05301
05302 curGroupPassword = recGroupPassword;
05303 } else
05304 curGroupPassword = "";
05305
05306 if (groupnameAsAllProg)
05307 groupDisplayName = tr(recGroup);
05308
05309 if (gContext->GetNumSetting("RememberRecGroup",1))
05310 gContext->SaveSetting("DisplayRecGroup", recGroup);
05311
05312 if (recGroupType[recGroup] == "recgroup")
05313 gContext->SaveSetting("DisplayRecGroupIsCategory", 0);
05314 else
05315 gContext->SaveSetting("DisplayRecGroupIsCategory", 1);
05316 }
05317
05318 QString PlaybackBox::getRecGroupPassword(QString group)
05319 {
05320 return ProgramInfo::GetRecGroupPassword(group);
05321 }
05322
05323 void PlaybackBox::fillRecGroupPasswordCache(void)
05324 {
05325 recGroupPwCache.clear();
05326
05327 MSqlQuery query(MSqlQuery::InitCon());
05328 query.prepare("SELECT recgroup, password "
05329 "FROM recgrouppassword "
05330 "WHERE password is not null "
05331 "AND password <> '' ;");
05332
05333 if (query.exec() && query.isActive() && query.size() > 0)
05334 while (query.next())
05335 {
05336 QString recgroup = QString::fromUtf8(query.value(0).toString());
05337 recGroupPwCache[recgroup] =
05338 query.value(1).toString();
05339 }
05340 }
05341
05342 void PlaybackBox::doPlaylistChangeRecGroup(void)
05343 {
05344
05345
05346 if (delitem)
05347 {
05348 delete delitem;
05349 delitem = NULL;
05350 }
05351
05352 showRecGroupChanger();
05353 }
05354
05355 void PlaybackBox::showRecGroupChanger(void)
05356 {
05357 if (!expectingPopup)
05358 return;
05359
05360 cancelPopup();
05361
05362 initRecGroupPopup(tr("Recording Group"), "showRecGroupChanger");
05363
05364 MSqlQuery query(MSqlQuery::InitCon());
05365 query.prepare(
05366 "SELECT recgroup, COUNT(title) FROM recorded "
05367 "WHERE deletepending = 0 GROUP BY recgroup");
05368
05369 QStringList groups;
05370 QString itemStr;
05371 QString dispGroup;
05372
05373 if (query.exec() && query.isActive() && query.size() > 0)
05374 {
05375 while (query.next())
05376 {
05377 if (query.value(1).toInt() == 1)
05378 itemStr = tr("item");
05379 else
05380 itemStr = tr("items");
05381
05382 dispGroup = QString::fromUtf8(query.value(0).toString());
05383
05384 if (dispGroup == "Default")
05385 dispGroup = tr("Default");
05386 else if (dispGroup == "LiveTV")
05387 dispGroup = tr("LiveTV");
05388 else if (dispGroup == "Deleted")
05389 dispGroup = tr("Deleted");
05390
05391 groups += QString("%1 [%2 %3]").arg(dispGroup)
05392 .arg(query.value(1).toInt()).arg(itemStr);
05393 }
05394 }
05395 groups.sort();
05396
05397 recGroupListBox = new MythListBox(recGroupPopup);
05398 recGroupListBox->insertStringList(groups);
05399 recGroupPopup->addWidget(recGroupListBox);
05400
05401 recGroupLineEdit = new MythLineEdit(recGroupPopup);
05402 recGroupLineEdit->setText("");
05403 recGroupLineEdit->selectAll();
05404 recGroupPopup->addWidget(recGroupLineEdit);
05405
05406 if (delitem && (delitem->recgroup != "Default"))
05407 {
05408 recGroupLineEdit->setText(delitem->recgroup);
05409 recGroupListBox->setCurrentItem(
05410 recGroupListBox->index(recGroupListBox->findItem(delitem->recgroup)));
05411 }
05412 else
05413 {
05414 QString dispGroup = recGroup;
05415
05416 if (recGroup == "Default")
05417 dispGroup = tr("Default");
05418 else if (recGroup == "LiveTV")
05419 dispGroup = tr("LiveTV");
05420 else if (recGroup == "Deleted")
05421 dispGroup = tr("Deleted");
05422
05423 recGroupLineEdit->setText(dispGroup);
05424 recGroupListBox->setCurrentItem(recGroupListBox->index(
05425 recGroupListBox->findItem(dispGroup)));
05426 }
05427
05428 recGroupOkButton = new MythPushButton(recGroupPopup);
05429 recGroupOkButton->setText(tr("OK"));
05430 recGroupPopup->addWidget(recGroupOkButton);
05431
05432 recGroupListBox->setFocus();
05433
05434 connect(recGroupListBox, SIGNAL(accepted(int)),
05435 recGroupPopup, SLOT(AcceptItem(int)));
05436 connect(recGroupListBox, SIGNAL(currentChanged(QListBoxItem *)), this,
05437 SLOT(recGroupChangerListBoxChanged()));
05438 connect(recGroupOkButton, SIGNAL(clicked()), recGroupPopup, SLOT(accept()));
05439
05440 DialogCode result = recGroupPopup->ExecPopup();
05441
05442 if (result != MythDialog::Rejected)
05443 setRecGroup();
05444
05445 closeRecGroupPopup(result != MythDialog::Rejected);
05446 }
05447
05448 void PlaybackBox::doPlaylistChangePlayGroup(void)
05449 {
05450
05451
05452 if (delitem)
05453 {
05454 delete delitem;
05455 delitem = NULL;
05456 }
05457
05458 showPlayGroupChanger();
05459 }
05460
05461 void PlaybackBox::showPlayGroupChanger(void)
05462 {
05463 if (!expectingPopup)
05464 return;
05465
05466 cancelPopup();
05467
05468 initRecGroupPopup(tr("Playback Group"), "showPlayGroupChanger");
05469
05470 recGroupListBox = new MythListBox(recGroupPopup);
05471 recGroupListBox->insertItem(tr("Default"));
05472 recGroupListBox->insertStringList(PlayGroup::GetNames());
05473 recGroupPopup->addWidget(recGroupListBox);
05474
05475 if (delitem && (delitem->playgroup != "Default"))
05476 {
05477 recGroupListBox->setCurrentItem(
05478 recGroupListBox->index(recGroupListBox->findItem(delitem->playgroup)));
05479 }
05480 else
05481 {
05482 QString dispGroup = tr("Default");
05483 recGroupListBox->setCurrentItem(recGroupListBox->index(
05484 recGroupListBox->findItem(dispGroup)));
05485 }
05486
05487 recGroupListBox->setFocus();
05488 connect(recGroupListBox, SIGNAL(accepted(int)),
05489 recGroupPopup, SLOT(AcceptItem(int)));
05490
05491 DialogCode result = recGroupPopup->ExecPopup();
05492
05493 if (result != MythDialog::Rejected)
05494 setPlayGroup();
05495
05496 closeRecGroupPopup(result != MythDialog::Rejected);
05497 }
05498
05499 void PlaybackBox::showRecTitleChanger()
05500 {
05501 if (!expectingPopup)
05502 return;
05503
05504 cancelPopup();
05505
05506 initRecGroupPopup(tr("Recording Title"), "showRecTitleChanger");
05507
05508 recGroupPopup->addLabel(tr("Title"));
05509 recGroupLineEdit = new MythLineEdit(recGroupPopup);
05510 recGroupLineEdit->setText(delitem->title);
05511 recGroupLineEdit->selectAll();
05512 recGroupPopup->addWidget(recGroupLineEdit);
05513
05514 recGroupPopup->addLabel(tr("Subtitle"));
05515 recGroupLineEdit1 = new MythLineEdit(recGroupPopup);
05516 recGroupLineEdit1->setText(delitem->subtitle);
05517 recGroupLineEdit1->selectAll();
05518 recGroupPopup->addWidget(recGroupLineEdit1);
05519
05520 recGroupLineEdit->setFocus();
05521
05522 recGroupOkButton = new MythPushButton(recGroupPopup);
05523 recGroupOkButton->setText(tr("OK"));
05524 recGroupPopup->addWidget(recGroupOkButton);
05525
05526 connect(recGroupOkButton, SIGNAL(clicked()), recGroupPopup, SLOT(accept()));
05527
05528 DialogCode result = recGroupPopup->ExecPopup();
05529
05530 if (result == MythDialog::Accepted)
05531 setRecTitle();
05532
05533 closeRecGroupPopup(result == MythDialog::Accepted);
05534
05535 delete delitem;
05536 delitem = NULL;
05537 }
05538
05539 void PlaybackBox::setRecGroup(void)
05540 {
05541 QString newRecGroup = recGroupLineEdit->text();
05542 ProgramInfo *tmpItem;
05543
05544 if (newRecGroup != "" )
05545 {
05546 if (newRecGroup == tr("Default"))
05547 newRecGroup = "Default";
05548 else if (newRecGroup == tr("LiveTV"))
05549 newRecGroup = "LiveTV";
05550 else if (newRecGroup == tr("Deleted"))
05551 newRecGroup = "Deleted";
05552
05553 if (delitem)
05554 {
05555 if ((delitem->recgroup == "LiveTV") &&
05556 (newRecGroup != "LiveTV"))
05557 delitem->SetAutoExpire(
05558 gContext->GetNumSetting("AutoExpireDefault", 0));
05559 else if ((delitem->recgroup != "LiveTV") &&
05560 (newRecGroup == "LiveTV"))
05561 delitem->SetAutoExpire(kLiveTVAutoExpire);
05562
05563
05564 tmpItem = findMatchingProg(delitem);
05565 if (tmpItem)
05566 tmpItem->ApplyRecordRecGroupChange(newRecGroup);
05567 } else if (playList.count() > 0) {
05568 QStringList::Iterator it;
05569
05570 for (it = playList.begin(); it != playList.end(); ++it )
05571 {
05572 tmpItem = findMatchingProg(*it);
05573 if (tmpItem)
05574 {
05575 if ((tmpItem->recgroup == "LiveTV") &&
05576 (newRecGroup != "LiveTV"))
05577 tmpItem->SetAutoExpire(
05578 gContext->GetNumSetting("AutoExpireDefault", 0));
05579 else if ((tmpItem->recgroup != "LiveTV") &&
05580 (newRecGroup == "LiveTV"))
05581 tmpItem->SetAutoExpire(kLiveTVAutoExpire);
05582
05583 tmpItem->ApplyRecordRecGroupChange(newRecGroup);
05584 }
05585 }
05586 playList.clear();
05587 }
05588 }
05589 }
05590
05591 void PlaybackBox::setPlayGroup(void)
05592 {
05593 QString newPlayGroup = recGroupListBox->currentText();
05594 ProgramInfo *tmpItem;
05595
05596 if (newPlayGroup == tr("Default"))
05597 newPlayGroup = "Default";
05598
05599 if (delitem)
05600 {
05601 tmpItem = findMatchingProg(delitem);
05602 if (tmpItem)
05603 tmpItem->ApplyRecordPlayGroupChange(newPlayGroup);
05604 }
05605 else if (playList.count() > 0)
05606 {
05607 QStringList::Iterator it;
05608
05609 for (it = playList.begin(); it != playList.end(); ++it )
05610 {
05611 tmpItem = findMatchingProg(*it);
05612 if (tmpItem)
05613 tmpItem->ApplyRecordPlayGroupChange(newPlayGroup);
05614 }
05615 playList.clear();
05616 }
05617 }
05618
05619 void PlaybackBox::setRecTitle()
05620 {
05621 QString newRecTitle = recGroupLineEdit->text();
05622 QString newRecSubtitle = recGroupLineEdit1->text();
05623 ProgramInfo *tmpItem;
05624
05625 if (newRecTitle == "")
05626 return;
05627
05628 tmpItem = findMatchingProg(delitem);
05629 if (tmpItem)
05630 tmpItem->ApplyRecordRecTitleChange(newRecTitle, newRecSubtitle);
05631
05632 inTitle = gContext->GetNumSetting("PlaybackBoxStartInTitle", 0);
05633 titleIndex = 0;
05634 progIndex = 0;
05635
05636 connected = FillList(true);
05637 paintSkipUpdate = false;
05638 update(drawTotalBounds);
05639 }
05640
05641 void PlaybackBox::recGroupChangerListBoxChanged(void)
05642 {
05643 if (!recGroupPopup || !recGroupListBox || !recGroupLineEdit)
05644 return;
05645
05646 recGroupLineEdit->setText(
05647 recGroupListBox->currentText().section('[', 0, 0).simplifyWhiteSpace());
05648 }
05649
05650 void PlaybackBox::showRecGroupPasswordChanger(void)
05651 {
05652 if (!expectingPopup)
05653 return;
05654
05655 cancelPopup();
05656
05657 initRecGroupPopup(tr("Group Password"),
05658 "showRecGroupPasswordChanger");
05659
05660 QGridLayout *grid = new QGridLayout(3, 2, (int)(10 * wmult));
05661
05662 QLabel *label = new QLabel(tr("Recording Group:"), recGroupPopup);
05663 label->setAlignment(Qt::WordBreak | Qt::AlignLeft);
05664 label->setBackgroundOrigin(ParentOrigin);
05665 label->setPaletteForegroundColor(drawPopupFgColor);
05666 grid->addWidget(label, 0, 0, Qt::AlignLeft);
05667
05668 if ((recGroup == "Default") || (recGroup == "All Programs") ||
05669 (recGroup == "LiveTV") || (recGroup == "Deleted"))
05670 label = new QLabel(tr(recGroup), recGroupPopup);
05671 else
05672 label = new QLabel(recGroup, recGroupPopup);
05673
05674 label->setAlignment(Qt::WordBreak | Qt::AlignLeft);
05675 label->setBackgroundOrigin(ParentOrigin);
05676 label->setPaletteForegroundColor(drawPopupFgColor);
05677 grid->addWidget(label, 0, 1, Qt::AlignLeft);
05678
05679 label = new QLabel(tr("Old Password:"), recGroupPopup);
05680 label->setAlignment(Qt::WordBreak | Qt::AlignLeft);
05681 label->setBackgroundOrigin(ParentOrigin);
05682 label->setPaletteForegroundColor(drawPopupFgColor);
05683 grid->addWidget(label, 1, 0, Qt::AlignLeft);
05684
05685 recGroupOldPassword = new MythLineEdit(recGroupPopup);
05686 recGroupOldPassword->setText("");
05687 recGroupOldPassword->selectAll();
05688 grid->addWidget(recGroupOldPassword, 1, 1, Qt::AlignLeft);
05689
05690 label = new QLabel(tr("New Password:"), recGroupPopup);
05691 label->setAlignment(Qt::WordBreak | Qt::AlignLeft);
05692 label->setBackgroundOrigin(ParentOrigin);
05693 label->setPaletteForegroundColor(drawPopupFgColor);
05694 grid->addWidget(label, 2, 0, Qt::AlignLeft);
05695
05696 recGroupNewPassword = new MythLineEdit(recGroupPopup);
05697 recGroupNewPassword->setText("");
05698 recGroupNewPassword->selectAll();
05699 grid->addWidget(recGroupNewPassword, 2, 1, Qt::AlignLeft);
05700
05701 recGroupPopup->addLayout(grid);
05702
05703 recGroupOkButton = new MythPushButton(recGroupPopup);
05704 recGroupOkButton->setText(tr("OK"));
05705 recGroupPopup->addWidget(recGroupOkButton);
05706
05707 recGroupChooserPassword = getRecGroupPassword(recGroup);
05708
05709 recGroupOldPassword->setEchoMode(QLineEdit::Password);
05710 recGroupNewPassword->setEchoMode(QLineEdit::Password);
05711
05712
05713 recGroupOldPasswordChanged(QString::null);
05714 if (IsRecGroupPasswordCorrect(QString::null))
05715 recGroupNewPassword->setFocus();
05716 else
05717 recGroupOldPassword->setFocus();
05718
05719 connect(recGroupOldPassword, SIGNAL(textChanged(const QString &)), this,
05720 SLOT(recGroupOldPasswordChanged(const QString &)));
05721 connect(recGroupOkButton, SIGNAL(clicked()), recGroupPopup, SLOT(accept()));
05722
05723 if (recGroupPopup->ExecPopup() == MythDialog::Accepted)
05724 {
05725 SetRecGroupPassword(recGroupOldPassword->text(),
05726 recGroupNewPassword->text());
05727 }
05728
05729 closeRecGroupPopup(false);
05730 }
05731
05732 void PlaybackBox::SetRecGroupPassword(const QString &oldPassword,
05733 const QString &newPassword)
05734 {
05735 if (oldPassword != recGroupPassword)
05736 {
05737 VERBOSE(VB_IMPORTANT, "Not setting password: "
05738 "oldPassword != recGroupPassword");
05739 return;
05740 }
05741
05742 if (recGroup == "All Programs")
05743 {
05744 gContext->SaveSetting("AllRecGroupPassword", newPassword);
05745 }
05746 else
05747 {
05748 MSqlQuery query(MSqlQuery::InitCon());
05749
05750 query.prepare("DELETE FROM recgrouppassword "
05751 "WHERE recgroup = :RECGROUP ;");
05752 query.bindValue(":RECGROUP", recGroup.utf8());
05753
05754 query.exec();
05755
05756 if (newPassword != "")
05757 {
05758 query.prepare("INSERT INTO recgrouppassword "
05759 "(recgroup, password) VALUES "
05760 "( :RECGROUP , :PASSWD )");
05761 query.bindValue(":RECGROUP", recGroup.utf8());
05762 query.bindValue(":PASSWD", newPassword);
05763
05764 query.exec();
05765 }
05766 }
05767
05768 recGroupPassword = QDeepCopy<QString>(newPassword);
05769 }
05770
05771 bool PlaybackBox::IsRecGroupPasswordCorrect(const QString &newText) const
05772 {
05773 return ((newText == recGroupChooserPassword) ||
05774 (newText.isEmpty() && recGroupChooserPassword.isEmpty()));
05775 }
05776
05777 void PlaybackBox::recGroupOldPasswordChanged(const QString &newText)
05778 {
05779 if (recGroupOkButton)
05780 recGroupOkButton->setEnabled(IsRecGroupPasswordCorrect(newText));
05781 }
05782
05783 void PlaybackBox::clearProgramCache(void)
05784 {
05785 if (!progCache)
05786 return;
05787
05788 vector<ProgramInfo *>::iterator i = progCache->begin();
05789 for ( ; i != progCache->end(); i++)
05790 delete *i;
05791 delete progCache;
05792 progCache = NULL;
05793 }
05794
05795 void PlaybackBox::EmbedTVWindow(void)
05796 {
05797 if (playbackVideoContainer && m_player)
05798 {
05799 m_player->EmbedOutput(this->winId(), drawVideoBounds.x(),
05800 drawVideoBounds.y(), drawVideoBounds.width(),
05801 drawVideoBounds.height());
05802 }
05803 }
05804
05805