00001 #include <qlayout.h>
00002 #include <qpushbutton.h>
00003 #include <qbuttongroup.h>
00004 #include <qlabel.h>
00005 #include <qcursor.h>
00006 #include <qsqldatabase.h>
00007 #include <qdatetime.h>
00008 #include <qapplication.h>
00009 #include <qregexp.h>
00010 #include <qheader.h>
00011
00012 #include <stdlib.h>
00013
00014 #include <iostream>
00015 using namespace std;
00016
00017 #include "viewscheduled.h"
00018 #include "scheduledrecording.h"
00019 #include "customedit.h"
00020 #include "proglist.h"
00021 #include "tv_play.h"
00022
00023 #include "exitcodes.h"
00024 #include "dialogbox.h"
00025 #include "mythcontext.h"
00026 #include "remoteutil.h"
00027
00028 QWaitCondition vsbIsVisibleCond;
00029
00030 void *ViewScheduled::RunViewScheduled(void *player, bool showTV)
00031 {
00032 qApp->lock();
00033
00034 ViewScheduled *vsb = new ViewScheduled(gContext->GetMainWindow(),
00035 "view scheduled", (TV*)player, showTV);
00036 vsb->Show();
00037 qApp->unlock();
00038 vsbIsVisibleCond.wait();
00039 delete vsb;
00040
00041 return NULL;
00042 }
00043
00044 ViewScheduled::ViewScheduled(MythMainWindow *parent, const char *name,
00045 TV* player, bool showTV)
00046 : MythDialog(parent, name)
00047 {
00048 dateformat = gContext->GetSetting("ShortDateFormat", "M/d");
00049 timeformat = gContext->GetSetting("TimeFormat", "h:mm AP");
00050 channelFormat = gContext->GetSetting("ChannelFormat", "<num> <sign>");
00051 showAll = !gContext->GetNumSetting("ViewSchedShowLevel", 0);
00052
00053 fullRect = QRect(0, 0, size().width(), size().height());
00054 listRect = QRect(0, 0, 0, 0);
00055 infoRect = QRect(0, 0, 0, 0);
00056 conflictRect = QRect(0, 0, 0, 0);
00057 showLevelRect = QRect(0, 0, 0, 0);
00058 recStatusRect = QRect(0, 0, 0, 0);
00059
00060 m_player = player;
00061 theme = new XMLParse();
00062 theme->SetWMult(wmult);
00063 theme->SetHMult(hmult);
00064 if (m_player && m_player->IsRunning() && showTV)
00065 {
00066 if (!theme->LoadTheme(xmldata, "conflict-video"))
00067 theme->LoadTheme(xmldata, "conflict");
00068 }
00069 else
00070 theme->LoadTheme(xmldata, "conflict");
00071 LoadWindow(xmldata);
00072
00073 if (m_player)
00074 EmbedTVWindow();
00075
00076 LayerSet *container = theme->GetSet("selector");
00077 if (container)
00078 {
00079 UIListType *ltype = (UIListType *)container->GetType("conflictlist");
00080 if (ltype)
00081 listsize = ltype->GetItems();
00082 }
00083 else
00084 {
00085 VERBOSE(VB_IMPORTANT, "ViewScheduled::ViewScheduled(): "
00086 "Failed to get selector object.");
00087 exit(FRONTEND_BUGGY_EXIT_NO_SELECTOR);
00088 }
00089
00090 updateBackground();
00091
00092 inEvent = false;
00093 inFill = false;
00094 needFill = false;
00095
00096 curcard = 0;
00097 maxcard = 0;
00098 curinput = 0;
00099 maxinput = 0;
00100 listPos = 0;
00101 FillList();
00102
00103 setNoErase();
00104
00105 gContext->addListener(this);
00106 gContext->addCurrentLocation("ViewScheduled");
00107 }
00108
00109 ViewScheduled::~ViewScheduled()
00110 {
00111 gContext->SaveSetting("ViewSchedShowLevel", !showAll);
00112 gContext->removeListener(this);
00113 gContext->removeCurrentLocation();
00114
00115 delete theme;
00116 }
00117
00118 void ViewScheduled::keyPressEvent(QKeyEvent *e)
00119 {
00120 if (inEvent)
00121 return;
00122
00123 inEvent = true;
00124
00125 bool handled = false;
00126 QStringList actions;
00127 if (gContext->GetMainWindow()->TranslateKeyPress("TV Frontend", e, actions))
00128 {
00129 for (unsigned int i = 0; i < actions.size() && !handled; i++)
00130 {
00131 QString action = actions[i];
00132 handled = true;
00133
00134 if (action == "SELECT")
00135 selected();
00136 else if (action == "MENU" || action == "INFO")
00137 edit();
00138 else if (action == "CUSTOMEDIT")
00139 customEdit();
00140 else if (action == "DELETE")
00141 remove();
00142 else if (action == "UPCOMING")
00143 upcoming();
00144 else if (action == "DETAILS")
00145 details();
00146 else if (action == "ESCAPE" || action == "LEFT")
00147 {
00148 vsbIsVisibleCond.wakeAll();
00149 done(MythDialog::Accepted);
00150 }
00151 else if (action == "UP")
00152 cursorUp();
00153 else if (action == "DOWN")
00154 cursorDown();
00155 else if (action == "PAGEUP")
00156 pageUp();
00157 else if (action == "PAGEDOWN")
00158 pageDown();
00159 else if (action == "1")
00160 setShowAll(true);
00161 else if (action == "2")
00162 setShowAll(false);
00163 else if (action == "PREVVIEW" || action == "NEXTVIEW")
00164 setShowAll(!showAll);
00165 else if (action == "VIEWCARD")
00166 viewCards();
00167 else if (action == "VIEWINPUT")
00168 viewInputs();
00169 else
00170 handled = false;
00171 }
00172 }
00173
00174 if (!handled)
00175 MythDialog::keyPressEvent(e);
00176
00177 if (needFill)
00178 {
00179 do
00180 {
00181 needFill = false;
00182 FillList();
00183 } while (needFill);
00184
00185 update(fullRect);
00186 }
00187
00188 inEvent = false;
00189 }
00190
00191 void ViewScheduled::LoadWindow(QDomElement &element)
00192 {
00193 for (QDomNode child = element.firstChild(); !child.isNull();
00194 child = child.nextSibling())
00195 {
00196 QDomElement e = child.toElement();
00197 if (!e.isNull())
00198 {
00199 if (e.tagName() == "font")
00200 theme->parseFont(e);
00201 else if (e.tagName() == "container")
00202 parseContainer(e);
00203 else
00204 {
00205 VERBOSE(VB_IMPORTANT,
00206 QString("ViewScheduled: Unknown child element: %1. "
00207 "Ignoring.").arg(e.tagName()));
00208 }
00209 }
00210 }
00211 }
00212
00213 void ViewScheduled::parseContainer(QDomElement &element)
00214 {
00215 QRect area;
00216 QString name;
00217 int context;
00218 theme->parseContainer(element, name, context, area);
00219
00220 if (name.lower() == "selector")
00221 listRect = area;
00222 if (name.lower() == "program_info")
00223 infoRect = area;
00224 if (name.lower() == "conflict_info")
00225 conflictRect = area;
00226 if (name.lower() == "showlevel_info")
00227 showLevelRect = area;
00228 if (name.lower() == "status_info")
00229 recStatusRect = area;
00230 if (name.lower() == "tv_video")
00231 tvRect = area;
00232 }
00233
00234 void ViewScheduled::updateBackground(void)
00235 {
00236 QPixmap bground(size());
00237 bground.fill(this, 0, 0);
00238
00239 QPainter tmp(&bground);
00240
00241 LayerSet *container = theme->GetSet("background");
00242 if (!container)
00243 return;
00244
00245 container->Draw(&tmp, 0, 0);
00246
00247 tmp.end();
00248 myBackground = bground;
00249
00250 setPaletteBackgroundPixmap(myBackground);
00251 }
00252
00253 void ViewScheduled::paintEvent(QPaintEvent *e)
00254 {
00255 if (inFill)
00256 return;
00257
00258 QRect r = e->rect();
00259 QPainter p(this);
00260
00261 if (r.intersects(listRect))
00262 updateList(&p);
00263 if (r.intersects(infoRect))
00264 updateInfo(&p);
00265 if (r.intersects(conflictRect))
00266 updateConflict(&p);
00267 if (r.intersects(showLevelRect))
00268 updateShowLevel(&p);
00269 if (r.intersects(recStatusRect))
00270 updateRecStatus(&p);
00271 }
00272
00273 void ViewScheduled::cursorDown(bool page)
00274 {
00275 if (listPos < (int)recList.count() - 1)
00276 {
00277 listPos += (page ? listsize : 1);
00278 if (listPos > (int)recList.count() - 1)
00279 listPos = recList.count() - 1;
00280 update(fullRect);
00281 }
00282 }
00283
00284 void ViewScheduled::cursorUp(bool page)
00285 {
00286 if (listPos > 0)
00287 {
00288 listPos -= (page ? listsize : 1);
00289 if (listPos < 0)
00290 listPos = 0;
00291 update(fullRect);
00292 }
00293 }
00294
00295 void ViewScheduled::FillList(void)
00296 {
00297 inFill = true;
00298
00299 QString callsign;
00300 QDateTime startts, recstartts;
00301
00302 if (recList[listPos])
00303 {
00304 callsign = recList[listPos]->chansign;
00305 startts = recList[listPos]->startts;
00306 recstartts = recList[listPos]->recstartts;
00307 }
00308
00309 recList.FromScheduler(conflictBool);
00310
00311 QDateTime now = QDateTime::currentDateTime();
00312
00313 QMap<int, int> toomanycounts;
00314
00315 ProgramInfo *p = recList.first();
00316 while (p)
00317 {
00318 if ((p->recendts >= now || p->endts >= now) &&
00319 (showAll || p->recstatus <= rsWillRecord ||
00320 p->recstatus == rsDontRecord ||
00321 (p->recstatus == rsTooManyRecordings &&
00322 ++toomanycounts[p->recordid] <= 1) ||
00323 (p->recstatus > rsTooManyRecordings &&
00324 p->recstatus != rsRepeat &&
00325 p->recstatus != rsNeverRecord)))
00326 {
00327 cardref[p->cardid]++;
00328 if (p->cardid > maxcard)
00329 maxcard = p->cardid;
00330
00331 inputref[p->inputid]++;
00332 if (p->inputid > maxinput)
00333 maxinput = p->inputid;
00334
00335 p = recList.next();
00336 }
00337 else
00338 {
00339 recList.remove();
00340 p = recList.current();
00341 }
00342 }
00343
00344 if (!callsign.isNull())
00345 {
00346 listPos = recList.count() - 1;
00347 int i;
00348 for (i = listPos; i >= 0; i--)
00349 {
00350 if (callsign == recList[i]->chansign &&
00351 startts == recList[i]->startts)
00352 {
00353 listPos = i;
00354 break;
00355 }
00356 else if (recstartts <= recList[i]->recstartts)
00357 listPos = i;
00358 }
00359 }
00360
00361 if (conflictBool)
00362 {
00363
00364 for (uint i = 0; i < recList.count(); i++)
00365 {
00366 ProgramInfo *p = recList[i];
00367 if (p->recstatus == rsConflict)
00368 {
00369 conflictDate = p->recstartts.date();
00370 break;
00371 }
00372 }
00373 }
00374
00375 inFill = false;
00376 }
00377
00378 void ViewScheduled::updateList(QPainter *p)
00379 {
00380 QRect pr = listRect;
00381 QPixmap pix(pr.size());
00382 pix.fill(this, pr.topLeft());
00383 QPainter tmp(&pix);
00384
00385 LayerSet *container = theme->GetSet("selector");
00386 if (container)
00387 {
00388 UIListType *ltype = (UIListType *)container->GetType("conflictlist");
00389 if (ltype)
00390 {
00391 ltype->ResetList();
00392 ltype->SetActive(true);
00393
00394 int listCount = recList.count();
00395
00396 int skip;
00397 if (listCount <= listsize || listPos <= listsize / 2)
00398 skip = 0;
00399 else if (listPos >= listCount - listsize + listsize / 2)
00400 skip = listCount - listsize;
00401 else
00402 skip = listPos - listsize / 2;
00403
00404 ltype->SetUpArrow(skip > 0);
00405 ltype->SetDownArrow(skip + listsize < listCount);
00406
00407 int i;
00408 for (i = 0; i < listsize; i++)
00409 {
00410 if (i + skip >= listCount)
00411 break;
00412
00413 ProgramInfo *p = recList[skip+i];
00414
00415 QString temp;
00416
00417 temp = (p->recstartts).toString(dateformat);
00418 temp += " " + (p->recstartts).toString(timeformat);
00419 ltype->SetItemText(i, 1, temp);
00420
00421 ltype->SetItemText(i, 2, p->ChannelText(channelFormat));
00422
00423 temp = p->title;
00424 if ((p->subtitle).stripWhiteSpace().length() > 0)
00425 temp += " - \"" + p->subtitle + "\"";
00426 ltype->SetItemText(i, 3, temp);
00427
00428 temp = p->RecStatusChar();
00429 ltype->SetItemText(i, 4, temp);
00430
00431 if (i + skip == listPos)
00432 ltype->SetItemCurrent(i);
00433
00434 if (p->recstatus == rsRecording)
00435 ltype->EnableForcedFont(i, "recording");
00436 else if (p->recstatus == rsConflict ||
00437 p->recstatus == rsOffLine ||
00438 p->recstatus == rsAborted)
00439 ltype->EnableForcedFont(i, "conflictingrecording");
00440 else if (p->recstatus == rsWillRecord)
00441 {
00442 if ((curcard == 0 && curinput == 0) ||
00443 p->cardid == curcard || p->inputid == curinput)
00444 ltype->EnableForcedFont(i, "record");
00445 }
00446 else if (p->recstatus == rsRepeat ||
00447 p->recstatus == rsOtherShowing ||
00448 p->recstatus == rsNeverRecord ||
00449 (p->recstatus != rsDontRecord &&
00450 p->recstatus <= rsEarlierShowing))
00451 ltype->EnableForcedFont(i, "disabledrecording");
00452 }
00453 }
00454 }
00455
00456 if (recList.count() == 0)
00457 container = theme->GetSet("norecordings_list");
00458
00459 if (container)
00460 {
00461 container->Draw(&tmp, 0, 0);
00462 container->Draw(&tmp, 1, 0);
00463 container->Draw(&tmp, 2, 0);
00464 container->Draw(&tmp, 3, 0);
00465 container->Draw(&tmp, 4, 0);
00466 container->Draw(&tmp, 5, 0);
00467 container->Draw(&tmp, 6, 0);
00468 container->Draw(&tmp, 7, 0);
00469 container->Draw(&tmp, 8, 0);
00470 }
00471
00472 tmp.end();
00473 p->drawPixmap(pr.topLeft(), pix);
00474 }
00475
00476 void ViewScheduled::updateConflict(QPainter *p)
00477 {
00478 QRect pr = conflictRect;
00479 QPixmap pix(pr.size());
00480 pix.fill(this, pr.topLeft());
00481 QPainter tmp(&pix);
00482
00483 LayerSet *container = theme->GetSet("conflict_info");
00484 if (container)
00485 {
00486 UITextType *wtype = (UITextType *)container->GetType("warning");
00487 UITextType *stype = (UITextType *)container->GetType("status");
00488
00489
00490 if (!wtype)
00491 wtype = stype;
00492
00493 if (stype)
00494 {
00495 if (conflictBool)
00496 {
00497
00498 QString cstring = tr("Time Conflict");
00499 QDate now = QDate::currentDate();
00500 int daysToConflict = now.daysTo(conflictDate);
00501
00502 if (daysToConflict == 0)
00503 cstring = tr("Conflict Today");
00504 else if (daysToConflict > 0)
00505 cstring = QString(tr("Conflict ")) +
00506 conflictDate.toString(dateformat);
00507
00508 stype->SetText("");
00509 wtype->SetText(cstring);
00510 }
00511 else
00512 {
00513 wtype->SetText("");
00514 stype->SetText(tr("No Conflicts"));
00515 }
00516 }
00517 }
00518
00519 if (container)
00520 {
00521 container->Draw(&tmp, 4, 0);
00522 container->Draw(&tmp, 5, 0);
00523 container->Draw(&tmp, 6, 0);
00524 container->Draw(&tmp, 7, 0);
00525 container->Draw(&tmp, 8, 0);
00526 }
00527
00528 tmp.end();
00529 p->drawPixmap(pr.topLeft(), pix);
00530 }
00531
00532 void ViewScheduled::updateShowLevel(QPainter *p)
00533 {
00534 QRect pr = showLevelRect;
00535 QPixmap pix(pr.size());
00536 pix.fill(this, pr.topLeft());
00537 QPainter tmp(&pix);
00538
00539 LayerSet *container = theme->GetSet("showlevel_info");
00540 if (container)
00541 {
00542 UITextType *type = (UITextType *)container->GetType("showlevel");
00543 if (type)
00544 {
00545 if (showAll)
00546 type->SetText(tr("All"));
00547 else
00548 type->SetText(tr("Important"));
00549 }
00550 }
00551
00552 if (container)
00553 {
00554 container->Draw(&tmp, 4, 0);
00555 container->Draw(&tmp, 5, 0);
00556 container->Draw(&tmp, 6, 0);
00557 container->Draw(&tmp, 7, 0);
00558 container->Draw(&tmp, 8, 0);
00559 }
00560
00561 tmp.end();
00562 p->drawPixmap(pr.topLeft(), pix);
00563 }
00564
00565 void ViewScheduled::updateInfo(QPainter *p)
00566 {
00567 QRect pr = infoRect;
00568 QPixmap pix(pr.size());
00569 pix.fill(this, pr.topLeft());
00570 QPainter tmp(&pix);
00571 QMap<QString, QString> infoMap;
00572
00573 LayerSet *container = theme->GetSet("program_info");
00574 if (container)
00575 {
00576 ProgramInfo *p = recList[listPos];
00577 if (p)
00578 {
00579 p->ToMap(infoMap);
00580 container->ClearAllText();
00581 container->SetText(infoMap);
00582 }
00583 }
00584
00585 if (recList.count() == 0)
00586 container = theme->GetSet("norecordings_info");
00587
00588 if (container)
00589 {
00590 container->Draw(&tmp, 4, 0);
00591 container->Draw(&tmp, 5, 0);
00592 container->Draw(&tmp, 6, 0);
00593 container->Draw(&tmp, 7, 0);
00594 container->Draw(&tmp, 8, 0);
00595 }
00596
00597 tmp.end();
00598 p->drawPixmap(pr.topLeft(), pix);
00599 }
00600
00601 void ViewScheduled::updateRecStatus(QPainter *p)
00602 {
00603 QRect pr = recStatusRect;
00604 QPixmap pix(pr.size());
00605 pix.fill(this, pr.topLeft());
00606 QPainter tmp(&pix);
00607 QMap<QString, QString> infoMap;
00608
00609 LayerSet *container = theme->GetSet("status_info");
00610 if (container)
00611 {
00612 ProgramInfo *p = recList[listPos];
00613 if (p)
00614 {
00615 p->ToMap(infoMap);
00616 container->ClearAllText();
00617 container->SetText(infoMap);
00618 }
00619 }
00620
00621 if (container)
00622 {
00623 container->Draw(&tmp, 4, 0);
00624 container->Draw(&tmp, 5, 0);
00625 container->Draw(&tmp, 6, 0);
00626 container->Draw(&tmp, 7, 0);
00627 container->Draw(&tmp, 8, 0);
00628 }
00629
00630 tmp.end();
00631 p->drawPixmap(pr.topLeft(), pix);
00632 }
00633
00634 void ViewScheduled::edit()
00635 {
00636 ProgramInfo *p = recList[listPos];
00637 if (!p)
00638 return;
00639
00640 p->EditScheduled();
00641 }
00642
00643 void ViewScheduled::customEdit()
00644 {
00645 ProgramInfo *p = recList[listPos];
00646 if (!p)
00647 return;
00648
00649 CustomEdit *ce = new CustomEdit(gContext->GetMainWindow(),
00650 "customedit", p);
00651 ce->exec();
00652 delete ce;
00653 }
00654
00655 void ViewScheduled::remove()
00656 {
00657 ProgramInfo *p = recList[listPos];
00658 if (!p)
00659 return;
00660
00661 ScheduledRecording *record = new ScheduledRecording();
00662 int recid = p->recordid;
00663 record->loadByID(recid);
00664
00665 QString message =
00666 tr("Delete '%1' %2 rule?").arg(record->getRecordTitle())
00667 .arg(p->RecTypeText());
00668
00669 bool ok = MythPopupBox::showOkCancelPopup(gContext->GetMainWindow(), "",
00670 message, false);
00671
00672 if (ok)
00673 {
00674 record->remove();
00675 ScheduledRecording::signalChange(recid);
00676 }
00677 record->deleteLater();
00678
00679 EmbedTVWindow();
00680 }
00681
00682 void ViewScheduled::upcoming()
00683 {
00684 ProgramInfo *p = recList[listPos];
00685
00686 if (!p)
00687 return;
00688
00689 ProgLister *pl = new ProgLister(plTitle, p->title, "",
00690 gContext->GetMainWindow(), "proglist");
00691 pl->exec();
00692 delete pl;
00693
00694 EmbedTVWindow();
00695 }
00696
00697 void ViewScheduled::details()
00698 {
00699 ProgramInfo *p = recList[listPos];
00700
00701 if (p)
00702 p->showDetails();
00703
00704 EmbedTVWindow();
00705 }
00706
00707 void ViewScheduled::selected()
00708 {
00709 ProgramInfo *p = recList[listPos];
00710 if (!p)
00711 return;
00712
00713 p->EditRecording();
00714
00715 EmbedTVWindow();
00716 }
00717
00718 void ViewScheduled::customEvent(QCustomEvent *e)
00719 {
00720 if ((MythEvent::Type)(e->type()) != MythEvent::MythEventMessage)
00721 return;
00722
00723 MythEvent *me = (MythEvent *)e;
00724 QString message = me->Message();
00725 if (message != "SCHEDULE_CHANGE")
00726 return;
00727
00728 if (inEvent)
00729 {
00730 needFill = true;
00731 return;
00732 }
00733
00734 inEvent = true;
00735
00736 do
00737 {
00738 needFill = false;
00739 FillList();
00740 } while (needFill);
00741
00742 update(fullRect);
00743
00744 inEvent = false;
00745 }
00746
00747 void ViewScheduled::setShowAll(bool all)
00748 {
00749 showAll = all;
00750
00751 needFill = true;
00752 }
00753
00754 void ViewScheduled::viewCards()
00755 {
00756 curinput = 0;
00757 needFill = true;
00758
00759 curcard++;
00760 while (curcard <= maxcard)
00761 {
00762 if (cardref[curcard] > 0)
00763 return;
00764 curcard++;
00765 }
00766 curcard = 0;
00767 }
00768
00769 void ViewScheduled::viewInputs()
00770 {
00771 curcard = 0;
00772 needFill = true;
00773
00774 curinput++;
00775 while (curinput <= maxinput)
00776 {
00777 if (inputref[curinput] > 0)
00778 return;
00779 curinput++;
00780 }
00781 curinput = 0;
00782 }
00783
00784 void ViewScheduled::EmbedTVWindow(void)
00785 {
00786 if (m_player)
00787 {
00788 m_player->EmbedOutput(this->winId(), tvRect.x(), tvRect.y(),
00789 tvRect.width(), tvRect.height());
00790 }
00791 }
00792