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 <iostream>
00013 #include <map>
00014 #include <vector>
00015 #include <algorithm>
00016 #include <cassert>
00017 using namespace std;
00018
00019 #include "proglist.h"
00020 #include "scheduledrecording.h"
00021 #include "customedit.h"
00022 #include "dialogbox.h"
00023 #include "mythcontext.h"
00024 #include "remoteutil.h"
00025 #include "mythdbcon.h"
00026 #include "channelutil.h"
00027
00028 ProgLister::ProgLister(ProgListType pltype,
00029 const QString &view, const QString &from,
00030 MythMainWindow *parent,
00031 const char *name)
00032 : MythDialog(parent, name)
00033 {
00034 type = pltype;
00035 addTables = from;
00036 startTime = QDateTime::currentDateTime();
00037 searchTime = startTime;
00038
00039 dayFormat = gContext->GetSetting("DateFormat");
00040 hourFormat = gContext->GetSetting("TimeFormat");
00041 timeFormat = gContext->GetSetting("ShortDateFormat") + " " + hourFormat;
00042 fullDateFormat = dayFormat + " " + hourFormat;
00043 channelOrdering = gContext->GetSetting("ChannelOrdering", "channum");
00044 channelFormat = gContext->GetSetting("ChannelFormat", "<num> <sign>");
00045
00046 switch (pltype)
00047 {
00048 case plTitleSearch: searchtype = kTitleSearch; break;
00049 case plKeywordSearch: searchtype = kKeywordSearch; break;
00050 case plPeopleSearch: searchtype = kPeopleSearch; break;
00051 case plPowerSearch: searchtype = kPowerSearch; break;
00052 case plSQLSearch: searchtype = kPowerSearch; break;
00053 case plStoredSearch: searchtype = kPowerSearch; break;
00054 default: searchtype = kNoSearch; break;
00055 }
00056
00057 allowEvents = true;
00058 allowUpdates = true;
00059 updateAll = false;
00060 refillAll = false;
00061 titleSort = false;
00062 reverseSort = false;
00063 useGenres = false;
00064
00065 fullRect = QRect(0, 0, size().width(), size().height());
00066 viewRect = QRect(0, 0, 0, 0);
00067 listRect = QRect(0, 0, 0, 0);
00068 infoRect = QRect(0, 0, 0, 0);
00069 theme = new XMLParse();
00070 theme->SetWMult(wmult);
00071 theme->SetHMult(hmult);
00072
00073 if (!theme->LoadTheme(xmldata, "programlist"))
00074 {
00075 DialogBox *dlg = new DialogBox(
00076 gContext->GetMainWindow(),
00077 QObject::tr(
00078 "The theme you are using does not contain the "
00079 "%1 element. Please contact the theme creator "
00080 "and ask if they could please update it.<br><br>"
00081 "The next screen will be empty. "
00082 "Escape out of it to return to the menu.")
00083 .arg("'programlist'"));
00084
00085 dlg->AddButton("OK");
00086 dlg->exec();
00087 dlg->deleteLater();
00088
00089 return;
00090 }
00091
00092 LoadWindow(xmldata);
00093
00094 LayerSet *container = theme->GetSet("selector");
00095 assert(container);
00096 UIListType *ltype = (UIListType *)container->GetType("proglist");
00097 if (ltype)
00098 listsize = ltype->GetItems();
00099
00100 choosePopup = NULL;
00101 chooseListBox = NULL;
00102 chooseLineEdit = NULL;
00103 chooseEditButton = NULL;
00104 chooseOkButton = NULL;
00105 chooseDeleteButton = NULL;
00106 chooseRecordButton = NULL;
00107 chooseDay = NULL;
00108 chooseHour = NULL;
00109
00110 powerPopup = NULL;
00111 powerTitleEdit = NULL;
00112 powerSubtitleEdit = NULL;
00113 powerDescEdit = NULL;
00114 powerCatType = NULL;
00115 powerGenre = NULL;
00116 powerStation = NULL;
00117
00118 curView = -1;
00119 fillViewList(view);
00120
00121 curItem = -1;
00122 fillItemList();
00123
00124 if (curView < 0)
00125 QApplication::postEvent(this, new MythEvent("CHOOSE_VIEW"));
00126
00127 updateBackground();
00128
00129 setNoErase();
00130
00131 gContext->addListener(this);
00132 gContext->addCurrentLocation("ProgLister");
00133 }
00134
00135 ProgLister::~ProgLister()
00136 {
00137 itemList.clear();
00138 gContext->removeListener(this);
00139 gContext->removeCurrentLocation();
00140 delete theme;
00141 }
00142
00143 void ProgLister::keyPressEvent(QKeyEvent *e)
00144 {
00145 if (!allowEvents)
00146 return;
00147
00148 allowEvents = false;
00149 bool handled = false;
00150
00151 QStringList actions;
00152 gContext->GetMainWindow()->TranslateKeyPress("TV Frontend", e, actions);
00153
00154 for (unsigned int i = 0; i < actions.size() && !handled; i++)
00155 {
00156 QString action = actions[i];
00157 handled = true;
00158
00159 if (action == "UP")
00160 cursorUp(false);
00161 else if (action == "DOWN")
00162 cursorDown(false);
00163 else if (action == "PAGEUP")
00164 cursorUp(true);
00165 else if (action == "PAGEDOWN")
00166 cursorDown(true);
00167 else if (action == "PREVVIEW")
00168 prevView();
00169 else if (action == "NEXTVIEW")
00170 nextView();
00171 else if (action == "MENU")
00172 chooseView();
00173 else if (action == "SELECT" || action == "RIGHT")
00174 select();
00175 else if (action == "LEFT")
00176 accept();
00177 else if (action == "INFO")
00178 edit();
00179 else if (action == "CUSTOMEDIT")
00180 customEdit();
00181 else if (action == "DELETE")
00182 remove();
00183 else if (action == "UPCOMING")
00184 upcoming();
00185 else if (action == "DETAILS")
00186 details();
00187 else if (action == "TOGGLERECORD")
00188 quickRecord();
00189 else if (action == "1")
00190 {
00191 if (titleSort == true)
00192 {
00193 titleSort = false;
00194 reverseSort = false;
00195 }
00196 else
00197 {
00198 reverseSort = !reverseSort;
00199 }
00200 refillAll = true;
00201 }
00202 else if (action == "2")
00203 {
00204 if (titleSort == false)
00205 {
00206 titleSort = true;
00207 reverseSort = false;
00208 }
00209 else
00210 {
00211 reverseSort = !reverseSort;
00212 }
00213 refillAll = true;
00214 }
00215 else
00216 handled = false;
00217 }
00218
00219 if (!handled)
00220 MythDialog::keyPressEvent(e);
00221
00222 if (refillAll)
00223 {
00224 allowUpdates = false;
00225 do
00226 {
00227 refillAll = false;
00228 fillItemList();
00229 } while (refillAll);
00230 allowUpdates = true;
00231 update(fullRect);
00232 }
00233
00234 allowEvents = true;
00235 }
00236
00237 void ProgLister::LoadWindow(QDomElement &element)
00238 {
00239 QString name;
00240 int context;
00241 QRect area;
00242
00243 for (QDomNode child = element.firstChild(); !child.isNull();
00244 child = child.nextSibling())
00245 {
00246 QDomElement e = child.toElement();
00247 if (!e.isNull())
00248 {
00249 if (e.tagName() == "font")
00250 theme->parseFont(e);
00251 else if (e.tagName() == "container")
00252 {
00253 theme->parseContainer(e, name, context, area);
00254 if (name.lower() == "view")
00255 viewRect = area;
00256 if (name.lower() == "selector")
00257 listRect = area;
00258 if (name.lower() == "program_info")
00259 infoRect = area;
00260 }
00261 else
00262 {
00263 VERBOSE(VB_IMPORTANT,
00264 QString("ProgLister::LoadWindow(): Error, unknown "
00265 "element '%1'. Ignoring.").arg(e.tagName()));
00266 }
00267 }
00268 }
00269 }
00270
00271 void ProgLister::updateBackground(void)
00272 {
00273 QPixmap bground(size());
00274 bground.fill(this, 0, 0);
00275
00276 QPainter tmp(&bground);
00277
00278 LayerSet *container = theme->GetSet("background");
00279 if (container)
00280 {
00281 UITextType *ltype = (UITextType *)container->GetType("sched");
00282 if (ltype)
00283 {
00284 QString value;
00285 switch (type)
00286 {
00287 case plTitle: value = tr("Program Listings"); break;
00288 case plNewListings: value = tr("New Title Search"); break;
00289 case plTitleSearch: value = tr("Title Search"); break;
00290 case plKeywordSearch: value = tr("Keyword Search"); break;
00291 case plPeopleSearch: value = tr("People Search"); break;
00292 case plStoredSearch: value = tr("Stored Search"); break;
00293 case plPowerSearch: value = tr("Power Search"); break;
00294 case plSQLSearch: value = tr("Power Search"); break;
00295 case plRecordid: value = tr("Rule Search"); break;
00296 case plCategory: value = tr("Category Search"); break;
00297 case plChannel: value = tr("Channel Search"); break;
00298 case plMovies: value = tr("Movie Search"); break;
00299 case plTime: value = tr("Time Search"); break;
00300 default: value = tr("Unknown Search"); break;
00301 }
00302 ltype->SetText(value);
00303 }
00304 container->Draw(&tmp, 0, 1);
00305 }
00306
00307 tmp.end();
00308
00309 setPaletteBackgroundPixmap(bground);
00310 }
00311
00312 void ProgLister::paintEvent(QPaintEvent *e)
00313 {
00314 if (!allowUpdates)
00315 {
00316 updateAll = true;
00317 return;
00318 }
00319
00320 QRect r = e->rect();
00321 QPainter p(this);
00322
00323
00324 if (updateAll || r.intersects(listRect))
00325 updateList(&p);
00326 if (updateAll || r.intersects(infoRect))
00327 updateInfo(&p);
00328 if (updateAll || r.intersects(viewRect))
00329 updateView(&p);
00330
00331 updateAll = false;
00332 }
00333
00334 void ProgLister::cursorDown(bool page)
00335 {
00336 if (curItem < (int)itemList.count() - 1)
00337 {
00338 curItem += (page ? listsize : 1);
00339 if (curItem > (int)itemList.count() - 1)
00340 curItem = itemList.count() - 1;
00341 update(fullRect);
00342 }
00343 }
00344
00345 void ProgLister::cursorUp(bool page)
00346 {
00347 if (curItem > 0)
00348 {
00349 curItem -= (page ? listsize : 1);
00350 if (curItem < 0)
00351 curItem = 0;
00352 update(fullRect);
00353 }
00354 }
00355
00356 void ProgLister::prevView(void)
00357 {
00358 if (type == plTime)
00359 {
00360 searchTime = searchTime.addSecs(-3600);
00361 curView = 0;
00362 viewList[curView] = searchTime.toString(fullDateFormat);
00363 viewTextList[curView] = viewList[curView];
00364 refillAll = true;
00365 return;
00366 }
00367
00368 if (viewList.count() < 2)
00369 return;
00370
00371 curView--;
00372 if (curView < 0)
00373 curView = viewList.count() - 1;
00374
00375 curItem = -1;
00376 refillAll = true;
00377 }
00378
00379 void ProgLister::nextView(void)
00380 {
00381 if (type == plTime)
00382 {
00383 searchTime = searchTime.addSecs(3600);
00384 curView = 0;
00385 viewList[curView] = searchTime.toString(fullDateFormat);
00386 viewTextList[curView] = viewList[curView];
00387 refillAll = true;
00388 return;
00389 }
00390 if (viewList.count() < 2)
00391 return;
00392
00393 curView++;
00394 if (curView >= (int)viewList.count())
00395 curView = 0;
00396
00397 curItem = -1;
00398 refillAll = true;
00399 }
00400
00401 void ProgLister::setViewFromList(int item)
00402 {
00403 int view = item;
00404
00405 if (!choosePopup || (!chooseListBox && !chooseEditButton))
00406 return;
00407
00408 if (type == plTitleSearch || type == plKeywordSearch ||
00409 type == plPeopleSearch)
00410 {
00411 view--;
00412 if (view < 0)
00413 {
00414 if (chooseLineEdit)
00415 chooseLineEdit->setFocus();
00416 return;
00417 }
00418 }
00419 if (type == plPowerSearch)
00420 {
00421 view--;
00422 if (view < 0)
00423 {
00424 if (chooseEditButton)
00425 powerEdit();
00426 return;
00427 }
00428 }
00429
00430 choosePopup->AcceptItem(item);
00431
00432 if (view == curView)
00433 return;
00434
00435 curView = view;
00436
00437 curItem = -1;
00438 refillAll = true;
00439 }
00440
00441 void ProgLister::chooseEditChanged(void)
00442 {
00443 if (!chooseOkButton || !chooseRecordButton || !chooseLineEdit)
00444 return;
00445
00446 chooseOkButton->setEnabled(chooseLineEdit->text().
00447 stripWhiteSpace().length() > 0);
00448 chooseRecordButton->setEnabled(chooseLineEdit->text().
00449 stripWhiteSpace().length() > 0);
00450 }
00451
00452 void ProgLister::chooseListBoxChanged(void)
00453 {
00454 if (!chooseListBox)
00455 return;
00456
00457 int view = chooseListBox->currentItem() - 1;
00458
00459 if (chooseLineEdit)
00460 {
00461 if (view < 0)
00462 chooseLineEdit->setText("");
00463 else
00464 chooseLineEdit->setText(viewList[view]);
00465
00466 chooseDeleteButton->setEnabled(view >= 0);
00467 }
00468 else if (chooseEditButton)
00469 {
00470 chooseDeleteButton->setEnabled(view >= 0);
00471 chooseRecordButton->setEnabled(view >= 0);
00472 }
00473 }
00474
00475 void ProgLister::updateKeywordInDB(const QString &text)
00476 {
00477 int oldview = chooseListBox->currentItem() - 1;
00478 int newview = viewList.findIndex(text);
00479
00480 QString qphrase = NULL;
00481
00482 if (newview < 0 || newview != oldview)
00483 {
00484 if (oldview >= 0)
00485 {
00486 qphrase = viewList[oldview].utf8();
00487
00488 MSqlQuery query(MSqlQuery::InitCon());
00489 query.prepare("DELETE FROM keyword "
00490 "WHERE phrase = :PHRASE AND searchtype = :TYPE;");
00491 query.bindValue(":PHRASE", qphrase);
00492 query.bindValue(":TYPE", searchtype);
00493 query.exec();
00494 }
00495 if (newview < 0)
00496 {
00497 qphrase = text.utf8();
00498
00499 MSqlQuery query(MSqlQuery::InitCon());
00500 query.prepare("REPLACE INTO keyword (phrase, searchtype)"
00501 "VALUES(:PHRASE, :TYPE );");
00502 query.bindValue(":PHRASE", qphrase);
00503 query.bindValue(":TYPE", searchtype);
00504 query.exec();
00505 }
00506 }
00507 }
00508
00509 void ProgLister::setViewFromEdit(void)
00510 {
00511 if (!choosePopup || !chooseListBox || !chooseLineEdit)
00512 return;
00513
00514 QString text = chooseLineEdit->text();
00515
00516 if (text.stripWhiteSpace().length() == 0)
00517 return;
00518
00519 updateKeywordInDB(text);
00520
00521 choosePopup->accept();
00522
00523 fillViewList(text);
00524
00525 curItem = -1;
00526 refillAll = true;
00527 }
00528
00529 void ProgLister::setViewFromPowerEdit()
00530 {
00531 if (!powerPopup || !choosePopup || !chooseListBox)
00532 return;
00533
00534 QString text = "";
00535 text = powerTitleEdit->text().replace(":","%").replace("*","%") + ":";
00536 text += powerSubtitleEdit->text().replace(":","%").replace("*","%") + ":";
00537 text += powerDescEdit->text().replace(":","%").replace("*","%") + ":";
00538
00539 if (powerCatType->currentItem() > 0)
00540 text += typeList[powerCatType->currentItem()];
00541 text += ":";
00542 if (powerGenre->currentItem() > 0)
00543 text += genreList[powerGenre->currentItem()];
00544 text += ":";
00545 if (powerStation->currentItem() > 0)
00546 text += stationList[powerStation->currentItem()];
00547
00548 if (text == ":::::")
00549 return;
00550
00551 updateKeywordInDB(text);
00552
00553 powerPopup->accept();
00554
00555 fillViewList(text);
00556
00557 curView = viewList.findIndex(text);
00558
00559 curItem = -1;
00560 refillAll = true;
00561 }
00562
00563 void ProgLister::addSearchRecord(void)
00564 {
00565 if (!choosePopup || !chooseListBox)
00566 return;
00567
00568 QString text = "";
00569 bool genreflag = false;
00570
00571 if (chooseLineEdit)
00572 text = chooseLineEdit->text();
00573 else if (chooseEditButton)
00574 text = chooseListBox->currentText();
00575 else
00576 return;
00577
00578 QString what = text;
00579
00580 if (text.stripWhiteSpace().length() == 0)
00581 return;
00582
00583 if (searchtype == kNoSearch)
00584 {
00585 VERBOSE(VB_IMPORTANT, "Unknown search in ProgLister");
00586 return;
00587 }
00588
00589 if (searchtype == kPowerSearch)
00590 {
00591 if (text == "" || text == ":::::")
00592 return;
00593
00594 MSqlBindings bindings;
00595 genreflag = powerStringToSQL(text.utf8(), what, bindings);
00596
00597 if (what == "")
00598 return;
00599
00600 MSqlEscapeAsAQuery(what, bindings);
00601 }
00602
00603 ScheduledRecording *record = new ScheduledRecording();
00604
00605 if (genreflag)
00606 {
00607 QString fromgenre = QString("LEFT JOIN programgenres ON "
00608 "program.chanid = programgenres.chanid AND "
00609 "program.starttime = programgenres.starttime ");
00610 record->loadBySearch(searchtype, text, fromgenre, what);
00611 }
00612 else
00613 {
00614 record->loadBySearch(searchtype, text, what);
00615 }
00616
00617 record->exec();
00618 record->deleteLater();
00619
00620 chooseListBox->setFocus();
00621 setViewFromEdit();
00622 }
00623
00624 void ProgLister::deleteKeyword(void)
00625 {
00626 if (!chooseDeleteButton || !chooseListBox)
00627 return;
00628
00629 int view = chooseListBox->currentItem() - 1;
00630
00631 if (view < 0)
00632 return;
00633
00634 QString text = viewList[view];
00635 QString qphrase = text.utf8();
00636
00637 MSqlQuery query(MSqlQuery::InitCon());
00638 query.prepare("DELETE FROM keyword "
00639 "WHERE phrase = :PHRASE AND searchtype = :TYPE;");
00640 query.bindValue(":PHRASE", qphrase);
00641 query.bindValue(":TYPE", searchtype);
00642 query.exec();
00643
00644 chooseListBox->removeItem(view + 1);
00645 viewList.remove(text);
00646 viewTextList.remove(text);
00647
00648 if (view < curView)
00649 curView--;
00650 else if (view == curView)
00651 curView = -1;
00652
00653 if (view >= (int)chooseListBox->count() - 1)
00654 view = chooseListBox->count() - 2;
00655
00656 chooseListBox->setSelected(view + 1, true);
00657
00658 if (viewList.count() < 1 && chooseLineEdit)
00659 chooseLineEdit->setFocus();
00660 else
00661 chooseListBox->setFocus();
00662 }
00663
00664 void ProgLister::setViewFromTime(void)
00665 {
00666 if (!choosePopup || !chooseDay || !chooseHour)
00667 return;
00668
00669 int dayOffset = chooseDay->currentItem() - 1;
00670 searchTime.setDate(startTime.addDays(dayOffset).date());
00671
00672 QTime m_hr;
00673 m_hr.setHMS(chooseHour->currentItem(), 0, 0);
00674 searchTime.setTime(m_hr);
00675
00676 curView = 0;
00677 viewList[curView] = searchTime.toString(fullDateFormat);
00678 viewTextList[curView] = viewList[curView];
00679
00680 choosePopup->accept();
00681
00682 curItem = -1;
00683 refillAll = true;
00684 }
00685
00686 void ProgLister::chooseView(void)
00687 {
00688 if (type == plChannel || type == plCategory || type == plMovies ||
00689 type == plNewListings || type == plStoredSearch)
00690 {
00691 if (viewList.count() < 1)
00692 return;
00693
00694 choosePopup = new MythPopupBox(gContext->GetMainWindow(), "");
00695
00696 QString msg;
00697 switch (type)
00698 {
00699 case plMovies: msg = tr("Select Rating"); break;
00700 case plChannel: msg = tr("Select Channel"); break;
00701 case plCategory: msg = tr("Select Category"); break;
00702 case plNewListings: msg = tr("Select List"); break;
00703 case plStoredSearch: msg = QString("%1\n%2")
00704 .arg(tr("Select a search stored from"))
00705 .arg(tr("Custom Record")); break;
00706 default: msg = tr("Select"); break;
00707 }
00708 choosePopup->addLabel(msg);
00709
00710 chooseListBox = new MythListBox(choosePopup);
00711 chooseListBox->setScrollBar(false);
00712 chooseListBox->setBottomScrollBar(false);
00713 chooseListBox->insertStringList(viewTextList);
00714 if (curView < 0)
00715 chooseListBox->setCurrentItem(0);
00716 else
00717 chooseListBox->setCurrentItem(curView);
00718 choosePopup->addWidget(chooseListBox);
00719
00720 if (type == plCategory)
00721 choosePopup->addLabel(tr("0 .. 9 moves to Nx10 percent in list"));
00722
00723 connect(chooseListBox, SIGNAL(accepted(int)),
00724 this, SLOT(setViewFromList(int)));
00725
00726 chooseListBox->setFocus();
00727 choosePopup->ExecPopup();
00728
00729 chooseListBox = NULL;
00730
00731 choosePopup->hide();
00732 choosePopup->deleteLater();
00733 choosePopup = NULL;
00734 }
00735 else if (type == plTitleSearch || type == plKeywordSearch ||
00736 type == plPeopleSearch)
00737 {
00738 int oldView = curView;
00739
00740 choosePopup = new MythPopupBox(gContext->GetMainWindow(), "");
00741 choosePopup->addLabel(tr("Select Phrase"));
00742
00743 chooseListBox = new MythListBox(choosePopup);
00744 chooseListBox->setScrollBar(false);
00745 chooseListBox->setBottomScrollBar(false);
00746 chooseListBox->insertItem(tr("<New Phrase>"));
00747 chooseListBox->insertStringList(viewTextList);
00748 if (curView < 0)
00749 chooseListBox->setCurrentItem(0);
00750 else
00751 chooseListBox->setCurrentItem(curView + 1);
00752 choosePopup->addWidget(chooseListBox);
00753
00754 chooseLineEdit = new MythRemoteLineEdit(choosePopup);
00755 if (curView < 0)
00756 chooseLineEdit->setText("");
00757 else
00758 chooseLineEdit->setText(viewList[curView]);
00759 choosePopup->addWidget(chooseLineEdit);
00760
00761 chooseOkButton = new MythPushButton(choosePopup);
00762 chooseOkButton->setText(tr("OK"));
00763 choosePopup->addWidget(chooseOkButton);
00764
00765 chooseDeleteButton = new MythPushButton(choosePopup);
00766 chooseDeleteButton->setText(tr("Delete"));
00767 choosePopup->addWidget(chooseDeleteButton);
00768
00769 chooseRecordButton = new MythPushButton(choosePopup);
00770 chooseRecordButton->setText(tr("Record"));
00771 choosePopup->addWidget(chooseRecordButton);
00772
00773 chooseOkButton->setEnabled(chooseLineEdit->text()
00774 .stripWhiteSpace().length() > 0);
00775 chooseDeleteButton->setEnabled(curView >= 0);
00776 chooseRecordButton->setEnabled(chooseLineEdit->text()
00777 .stripWhiteSpace().length() > 0);
00778
00779 connect(chooseListBox, SIGNAL(accepted(int)),
00780 this, SLOT(setViewFromList(int)));
00781 connect(chooseListBox, SIGNAL(menuButtonPressed(int)), chooseLineEdit, SLOT(setFocus()));
00782 connect(chooseListBox, SIGNAL(selectionChanged()), this, SLOT(chooseListBoxChanged()));
00783 connect(chooseLineEdit, SIGNAL(textChanged()), this, SLOT(chooseEditChanged()));
00784 connect(chooseOkButton, SIGNAL(clicked()), this, SLOT(setViewFromEdit()));
00785 connect(chooseDeleteButton, SIGNAL(clicked()), this, SLOT(deleteKeyword()));
00786 connect(chooseRecordButton, SIGNAL(clicked()), this, SLOT(addSearchRecord()));
00787
00788 if (viewList.count() < 1)
00789 chooseLineEdit->setFocus();
00790 else
00791 chooseListBox->setFocus();
00792 choosePopup->ExecPopup();
00793
00794 chooseLineEdit = NULL;
00795 chooseOkButton = NULL;
00796 chooseDeleteButton = NULL;
00797 chooseRecordButton = NULL;
00798 chooseListBox = NULL;
00799
00800 choosePopup->hide();
00801 choosePopup->deleteLater();
00802 choosePopup = NULL;
00803
00804 if (viewList.count() < 1 || (oldView < 0 && curView < 0))
00805 reject();
00806 else if (curView < 0)
00807 {
00808 curView = 0;
00809 curItem = -1;
00810 refillAll = true;
00811 }
00812 }
00813 else if (type == plPowerSearch)
00814 {
00815 int oldView = curView;
00816
00817 choosePopup = new MythPopupBox(gContext->GetMainWindow(), "");
00818 choosePopup->addLabel(tr("Select Search"));
00819
00820 chooseListBox = new MythListBox(choosePopup);
00821 chooseListBox->setScrollBar(false);
00822 chooseListBox->setBottomScrollBar(false);
00823 chooseListBox->insertItem(tr("<New Search>"));
00824 chooseListBox->insertStringList(viewTextList);
00825 if (curView < 0)
00826 chooseListBox->setCurrentItem(0);
00827 else
00828 chooseListBox->setCurrentItem(curView + 1);
00829 choosePopup->addWidget(chooseListBox);
00830
00831 chooseEditButton = new MythPushButton(choosePopup);
00832 chooseEditButton->setText(tr("Edit"));
00833 choosePopup->addWidget(chooseEditButton);
00834
00835 chooseDeleteButton = new MythPushButton(choosePopup);
00836 chooseDeleteButton->setText(tr("Delete"));
00837 choosePopup->addWidget(chooseDeleteButton);
00838
00839 chooseRecordButton = new MythPushButton(choosePopup);
00840 chooseRecordButton->setText(tr("Record"));
00841 choosePopup->addWidget(chooseRecordButton);
00842
00843 chooseDeleteButton->setEnabled(curView >= 0);
00844 chooseRecordButton->setEnabled(curView >= 0);
00845
00846 connect(chooseListBox, SIGNAL(accepted(int)),
00847 this, SLOT(setViewFromList(int)));
00848 connect(chooseListBox, SIGNAL(menuButtonPressed(int)),chooseEditButton,
00849 SLOT(setFocus()));
00850 connect(chooseListBox, SIGNAL(selectionChanged()), this,
00851 SLOT(chooseListBoxChanged()));
00852 connect(chooseEditButton, SIGNAL(clicked()), this,
00853 SLOT(powerEdit()));
00854 connect(chooseDeleteButton, SIGNAL(clicked()), this,
00855 SLOT(deleteKeyword()));
00856 connect(chooseRecordButton, SIGNAL(clicked()), this,
00857 SLOT(addSearchRecord()));
00858
00859 if (viewList.count() < 1)
00860 chooseEditButton->setFocus();
00861 else
00862 chooseListBox->setFocus();
00863 choosePopup->ExecPopup();
00864
00865 chooseEditButton = NULL;
00866 chooseDeleteButton = NULL;
00867 chooseRecordButton = NULL;
00868 chooseListBox = NULL;
00869
00870 choosePopup->hide();
00871 choosePopup->deleteLater();
00872 choosePopup = NULL;
00873
00874 if (viewList.count() < 1 || (oldView < 0 && curView < 0))
00875 reject();
00876 else if (curView < 0)
00877 {
00878 curView = 0;
00879 curItem = -1;
00880 refillAll = true;
00881 }
00882 }
00883 else if (type == plTime)
00884 {
00885 choosePopup = new MythPopupBox(gContext->GetMainWindow(), "");
00886 choosePopup->addLabel(tr("Select Time"));
00887
00888 chooseDay = new MythComboBox(false, choosePopup);
00889
00890 for(int m_index = -1; m_index <= 14; m_index++)
00891 {
00892 chooseDay->insertItem(startTime.addDays(m_index)
00893 .toString(dayFormat));
00894 if (startTime.addDays(m_index).toString("MMdd") ==
00895 searchTime.toString("MMdd"))
00896 chooseDay->setCurrentItem(chooseDay->count() - 1);
00897 }
00898 choosePopup->addWidget(chooseDay);
00899
00900 chooseHour = new MythComboBox(false, choosePopup);
00901
00902 QTime m_hr;
00903 for(int m_index = 0; m_index < 24; m_index++)
00904 {
00905 m_hr.setHMS(m_index, 0, 0);
00906 chooseHour->insertItem(m_hr.toString(hourFormat));
00907 if (m_hr.toString("hh") == searchTime.toString("hh"))
00908 chooseHour->setCurrentItem(m_index);
00909 }
00910 choosePopup->addWidget(chooseHour);
00911
00912 chooseOkButton = new MythPushButton(choosePopup);
00913 chooseOkButton->setText(tr("OK"));
00914 choosePopup->addWidget(chooseOkButton);
00915
00916 connect(chooseOkButton,
00917 SIGNAL(clicked()), this, SLOT(setViewFromTime()));
00918
00919 chooseOkButton->setFocus();
00920 choosePopup->ExecPopup();
00921
00922 chooseDay = NULL;
00923 chooseHour = NULL;
00924 chooseOkButton = NULL;
00925
00926 choosePopup->hide();
00927 choosePopup->deleteLater();
00928 choosePopup = NULL;
00929 }
00930 }
00931
00932 void ProgLister::powerEdit()
00933 {
00934 int view = chooseListBox->currentItem() - 1;
00935 QString text = ":::::";
00936
00937 if (view >= 0)
00938 text = viewList[view];
00939
00940 QStringList field = QStringList::split( ":", text, true);
00941
00942 if (field.count() != 6)
00943 {
00944 VERBOSE(VB_IMPORTANT, QString("Error. PowerSearch %1 has %2 fields")
00945 .arg(text).arg(field.count()));
00946 }
00947
00948 powerPopup = new MythPopupBox(gContext->GetMainWindow(), "");
00949 powerPopup->addLabel(tr("Edit Power Search Fields"));
00950
00951 powerPopup->addLabel(tr("Optional title phrase:"));
00952 powerTitleEdit = new MythRemoteLineEdit(powerPopup);
00953 powerPopup->addWidget(powerTitleEdit);
00954
00955 powerPopup->addLabel(tr("Optional subtitle phrase:"));
00956 powerSubtitleEdit = new MythRemoteLineEdit(powerPopup);
00957 powerPopup->addWidget(powerSubtitleEdit);
00958
00959 powerPopup->addLabel(tr("Optional description phrase:"));
00960 powerDescEdit = new MythRemoteLineEdit(powerPopup);
00961 powerPopup->addWidget(powerDescEdit);
00962
00963 powerCatType = new MythComboBox(false, powerPopup);
00964 powerCatType->insertItem(tr("(Any Program Type)"));
00965 typeList.clear();
00966 typeList << "";
00967 powerCatType->insertItem(tr("Movies"));
00968 typeList << "movie";
00969 powerCatType->insertItem(tr("Series"));
00970 typeList << "series";
00971 powerCatType->insertItem(tr("Show"));
00972 typeList << "tvshow";
00973 powerCatType->insertItem(tr("Sports"));
00974 typeList << "sports";
00975 powerCatType->setCurrentItem(typeList.findIndex(field[3]));
00976 powerPopup->addWidget(powerCatType);
00977
00978 powerGenre = new MythComboBox(false, powerPopup);
00979 powerGenre->insertItem(tr("(Any Genre)"));
00980 genreList.clear();
00981 genreList << "";
00982
00983 MSqlQuery query(MSqlQuery::InitCon());
00984
00985 query.prepare("SELECT genre FROM programgenres GROUP BY genre;");
00986 query.exec();
00987
00988 if (query.isActive() && query.size())
00989 {
00990 while (query.next())
00991 {
00992 QString category = query.value(0).toString();
00993 if (category <= " " || category == NULL)
00994 continue;
00995 category = QString::fromUtf8(query.value(0).toString());
00996 powerGenre->insertItem(category);
00997 genreList << category;
00998 if (category == field[4])
00999 powerGenre->setCurrentItem(powerGenre->count() - 1);
01000 }
01001 }
01002 powerPopup->addWidget(powerGenre);
01003
01004 powerStation = new MythComboBox(false, powerPopup);
01005 powerStation->insertItem(tr("(Any Station)"));
01006 stationList.clear();
01007 stationList << "";
01008
01009 DBChanList channels = ChannelUtil::GetChannels(0, true, "callsign");
01010 ChannelUtil::SortChannels(channels, channelOrdering, true);
01011
01012 for (uint i = 0; i < channels.size(); i++)
01013 {
01014 QString chantext = QDeepCopy<QString>(channelFormat);
01015 chantext
01016 .replace("<num>", channels[i].channum)
01017 .replace("<sign>", channels[i].callsign)
01018 .replace("<name>", channels[i].name);
01019
01020 viewList << QString::number(channels[i].chanid);
01021 viewTextList << chantext;
01022
01023 powerStation->insertItem(chantext);
01024 stationList << channels[i].callsign;
01025 if (channels[i].callsign == field[5])
01026 powerStation->setCurrentItem(powerStation->count() - 1);
01027 }
01028
01029 powerPopup->addWidget(powerStation);
01030
01031 powerOkButton = new MythPushButton(powerPopup);
01032 powerOkButton->setText(tr("OK"));
01033 powerPopup->addWidget(powerOkButton);
01034
01035 connect(powerOkButton, SIGNAL(clicked()), this,
01036 SLOT(setViewFromPowerEdit()));
01037
01038 powerTitleEdit->setText(field[0]);
01039 powerSubtitleEdit->setText(field[1]);
01040 powerDescEdit->setText(field[2]);
01041
01042 powerTitleEdit->setFocus();
01043 choosePopup->accept();
01044 powerPopup->ExecPopup();
01045
01046 powerTitleEdit = NULL;
01047 powerSubtitleEdit = NULL;
01048 powerDescEdit = NULL;
01049 powerCatType = NULL;
01050 powerGenre = NULL;
01051 powerStation = NULL;
01052 powerOkButton = NULL;
01053
01054 powerPopup->hide();
01055 powerPopup->deleteLater();
01056 powerPopup = NULL;
01057 }
01058
01059 bool ProgLister::powerStringToSQL(const QString &qphrase, QString &output,
01060 MSqlBindings &bindings)
01061 {
01062 int ret = 0;
01063 output = "";
01064 QString curfield;
01065
01066 QStringList field = QStringList::split(":", qphrase, true);
01067
01068 if (field.count() != 6)
01069 {
01070 VERBOSE(VB_IMPORTANT, QString("Error. PowerSearch %1 has %2 fields")
01071 .arg(qphrase).arg(field.count()));
01072 return ret;
01073 }
01074
01075 if (field[0])
01076 {
01077 curfield = "%" + field[0] + "%";
01078 output += "program.title LIKE :POWERTITLE ";
01079 bindings[":POWERTITLE"] = curfield;
01080 }
01081
01082 if (field[1])
01083 {
01084 if (output > "")
01085 output += "\nAND ";
01086
01087 curfield = "%" + field[1] + "%";
01088 output += "program.subtitle LIKE :POWERSUB ";
01089 bindings[":POWERSUB"] = curfield;
01090 }
01091
01092 if (field[2])
01093 {
01094 if (output > "")
01095 output += "\nAND ";
01096
01097 curfield = "%" + field[2] + "%";
01098 output += "program.description LIKE :POWERDESC ";
01099 bindings[":POWERDESC"] = curfield;
01100 }
01101
01102 if (field[3])
01103 {
01104 if (output > "")
01105 output += "\nAND ";
01106
01107 output += "program.category_type = :POWERCATTYPE ";
01108 bindings[":POWERCATTYPE"] = field[3];
01109 }
01110
01111 if (field[4])
01112 {
01113 if (output > "")
01114 output += "\nAND ";
01115
01116 output += "programgenres.genre = :POWERGENRE ";
01117 bindings[":POWERGENRE"] = field[4];
01118 ret = 1;
01119 }
01120
01121 if (field[5])
01122 {
01123 if (output > "")
01124 output += "\nAND ";
01125
01126 output += "channel.callsign = :POWERCALLSIGN ";
01127 bindings[":POWERCALLSIGN"] = field[5];
01128 }
01129 return ret;
01130 }
01131
01132 void ProgLister::quickRecord()
01133 {
01134 ProgramInfo *pi = itemList.at(curItem);
01135
01136 if (!pi)
01137 return;
01138
01139 pi->ToggleRecord();
01140 }
01141
01142 void ProgLister::select()
01143 {
01144 ProgramInfo *pi = itemList.at(curItem);
01145
01146 if (!pi)
01147 return;
01148
01149 pi->EditRecording();
01150 }
01151
01152 void ProgLister::edit()
01153 {
01154 ProgramInfo *pi = itemList.at(curItem);
01155
01156 if (!pi)
01157 return;
01158
01159 pi->EditScheduled();
01160 }
01161
01162 void ProgLister::customEdit()
01163 {
01164 ProgramInfo *pi = itemList.at(curItem);
01165
01166 if (!pi)
01167 return;
01168
01169 CustomEdit *ce = new CustomEdit(gContext->GetMainWindow(),
01170 "customedit", pi);
01171 ce->exec();
01172 delete ce;
01173 }
01174
01175 void ProgLister::remove()
01176 {
01177 ProgramInfo *pi = itemList.at(curItem);
01178
01179 if (!pi || pi->recordid <= 0)
01180 return;
01181
01182 ScheduledRecording *record = new ScheduledRecording();
01183 int recid = pi->recordid;
01184 record->loadByID(recid);
01185
01186 QString message =
01187 tr("Delete '%1' %2 rule?").arg(record->getRecordTitle())
01188 .arg(pi->RecTypeText());
01189
01190 bool ok = MythPopupBox::showOkCancelPopup(gContext->GetMainWindow(), "",
01191 message, false);
01192
01193 if (ok)
01194 {
01195 record->remove();
01196 ScheduledRecording::signalChange(recid);
01197 }
01198 record->deleteLater();
01199 }
01200
01201 void ProgLister::upcoming()
01202 {
01203 ProgramInfo *pi = itemList.at(curItem);
01204
01205 if (!pi || type == plTitle)
01206 return;
01207
01208 ProgLister *pl = new ProgLister(plTitle, pi->title, "",
01209 gContext->GetMainWindow(), "proglist");
01210 pl->exec();
01211 delete pl;
01212 }
01213
01214 void ProgLister::details()
01215 {
01216 ProgramInfo *pi = itemList.at(curItem);
01217
01218 if (pi)
01219 pi->showDetails();
01220 }
01221
01222 void ProgLister::fillViewList(const QString &view)
01223 {
01224 viewList.clear();
01225 viewTextList.clear();
01226
01227 if (type == plChannel)
01228 {
01229 DBChanList channels = ChannelUtil::GetChannels(0, true,
01230 "channum, chanid");
01231 ChannelUtil::SortChannels(channels, channelOrdering, true);
01232
01233 for (uint i = 0; i < channels.size(); i++)
01234 {
01235 QString chantext = QDeepCopy<QString>(channelFormat);
01236 chantext
01237 .replace("<num>", channels[i].channum)
01238 .replace("<sign>", channels[i].callsign)
01239 .replace("<name>", channels[i].name);
01240
01241 viewList << QString::number(channels[i].chanid);
01242 viewTextList << chantext;
01243 }
01244
01245 if (!view.isEmpty())
01246 curView = viewList.findIndex(view);
01247 }
01248 else if (type == plCategory)
01249 {
01250 QString startstr = startTime.toString("yyyy-MM-ddThh:mm:50");
01251 MSqlQuery query(MSqlQuery::InitCon());
01252 query.prepare("SELECT g1.genre, g2.genre "
01253 "FROM program "
01254 "JOIN programgenres g1 ON "
01255 " program.chanid = g1.chanid AND "
01256 " program.starttime = g1.starttime "
01257 "LEFT JOIN programgenres g2 ON "
01258 " g1.chanid = g2.chanid AND "
01259 " g1.starttime = g2.starttime "
01260 "WHERE program.endtime > :PGILSTART "
01261 "GROUP BY g1.genre, g2.genre;");
01262 query.bindValue(":PGILSTART", startstr);
01263 query.exec();
01264
01265 if (query.isActive() && query.size())
01266 {
01267 QString lastGenre1;
01268
01269 while (query.next())
01270 {
01271 QString genre1 = query.value(0).toString().utf8();
01272 if (genre1 <= " ")
01273 continue;
01274
01275 if (genre1 != lastGenre1)
01276 {
01277 viewList << genre1;
01278 viewTextList << genre1;
01279 lastGenre1 = genre1;
01280 }
01281
01282 QString genre2 = query.value(1).toString().utf8();
01283 if (genre2 <= " " || genre2 == genre1)
01284 continue;
01285
01286 viewList << genre1 + ":/:" + genre2;
01287 viewTextList << " " + genre1 + " / " + genre2;
01288 }
01289
01290 useGenres = true;
01291 }
01292 else
01293 {
01294 query.prepare("SELECT category "
01295 "FROM program "
01296 "WHERE program.endtime > :PGILSTART "
01297 "GROUP BY category;");
01298 query.bindValue(":PGILSTART", startstr);
01299 query.exec();
01300
01301 if (query.isActive() && query.size())
01302 {
01303 while (query.next())
01304 {
01305 QString category = query.value(0).toString();
01306 if (category <= " " || category == NULL)
01307 continue;
01308 category = QString::fromUtf8(query.value(0).toString());
01309 viewList << category;
01310 viewTextList << category;
01311 }
01312 }
01313
01314 useGenres = false;
01315 }
01316
01317 if (view != "")
01318 curView = viewList.findIndex(view);
01319 }
01320 else if (type == plTitleSearch || type == plKeywordSearch ||
01321 type == plPeopleSearch || type == plPowerSearch)
01322 {
01323 MSqlQuery query(MSqlQuery::InitCon());
01324 query.prepare("SELECT phrase FROM keyword "
01325 "WHERE searchtype = :SEARCHTYPE;");
01326 query.bindValue(":SEARCHTYPE", searchtype);
01327 query.exec();
01328
01329 if (query.isActive() && query.size())
01330 {
01331 while (query.next())
01332 {
01333 QString phrase = query.value(0).toString();
01334 if (phrase <= " ")
01335 continue;
01336 phrase = QString::fromUtf8(query.value(0).toString());
01337 viewList << phrase;
01338 viewTextList << phrase;
01339 }
01340 }
01341 if (view != "")
01342 {
01343 curView = viewList.findIndex(view);
01344
01345 if (curView < 0)
01346 {
01347 QString qphrase = view.utf8();
01348
01349 MSqlQuery query(MSqlQuery::InitCon());
01350 query.prepare("REPLACE INTO keyword (phrase, searchtype)"
01351 "VALUES(:VIEW, :SEARCHTYPE );");
01352 query.bindValue(":VIEW", qphrase);
01353 query.bindValue(":SEARCHTYPE", searchtype);
01354 query.exec();
01355
01356 viewList << qphrase;
01357 viewTextList << qphrase;
01358
01359 curView = viewList.count() - 1;
01360 }
01361 }
01362 else
01363 curView = -1;
01364 }
01365 else if (type == plTitle)
01366 {
01367 if (view != "")
01368 {
01369 viewList << view;
01370 viewTextList << view;
01371 curView = 0;
01372 }
01373 else
01374 curView = -1;
01375 }
01376 else if (type == plNewListings)
01377 {
01378 viewList << "all";
01379 viewTextList << tr("All");
01380
01381 viewList << "premieres";
01382 viewTextList << tr("Premieres");
01383
01384 viewList << "movies";
01385 viewTextList << tr("Movies");
01386
01387 viewList << "series";
01388 viewTextList << tr("Series");
01389
01390 viewList << "specials";
01391 viewTextList << tr("Specials");
01392 curView = 0;
01393 }
01394 else if (type == plMovies)
01395 {
01396 viewList << ">= 0.0";
01397 viewTextList << tr("All");
01398 viewList << "= 0.0";
01399 viewTextList << tr("Unrated");
01400 viewList << ">= 1.0";
01401 viewTextList << "****";
01402 viewList << ">= 0.875 AND program.stars < 1.0";
01403 viewTextList << "***/";
01404 viewList << ">= 0.75 AND program.stars < 0.875";
01405 viewTextList << "***";
01406 viewList << ">= 0.625 AND program.stars < 0.75";
01407 viewTextList << "**/";
01408 viewList << ">= 0.5 AND program.stars < 0.625";
01409 viewTextList << "**";
01410 viewList << ">= 0.375 AND program.stars < 0.5";
01411 viewTextList << "*/";
01412 viewList << ">= 0.25 AND program.stars < 0.375";
01413 viewTextList << "*";
01414 viewList << ">= 0.125 AND program.stars < 0.25";
01415 viewTextList << "/";
01416 viewList << ">= 0.875";
01417 viewTextList << tr("At least ***/");
01418 viewList << ">= 0.75";
01419 viewTextList << tr("At least ***");
01420 viewList << ">= 0.625";
01421 viewTextList << tr("At least **/");
01422 viewList << ">= 0.5";
01423 viewTextList << tr("At least **");
01424 viewList << ">= 0.375";
01425 viewTextList << tr("At least */");
01426 viewList << ">= 0.25";
01427 viewTextList << tr("At least *");
01428 viewList << ">= 0.125";
01429 viewTextList << tr("At least /");
01430 curView = 0;
01431 }
01432 else if (type == plTime)
01433 {
01434 curView = 0;
01435 viewList[curView] = searchTime.toString(fullDateFormat);
01436 viewTextList[curView] = viewList[curView];
01437 }
01438 else if (type == plSQLSearch)
01439 {
01440 curView = 0;
01441 viewList << view;
01442 viewTextList << tr("Power Recording Rule");
01443 }
01444 else if (type == plRecordid)
01445 {
01446 curView = 0;
01447
01448 MSqlQuery query(MSqlQuery::InitCon());
01449 query.prepare("SELECT title FROM record "
01450 "WHERE recordid = :RECORDID");
01451 query.bindValue(":RECORDID", view);
01452 query.exec();
01453
01454 if (query.isActive() && query.size())
01455 {
01456 if (query.next())
01457 {
01458 QString title = query.value(0).toString();
01459 title = QString::fromUtf8(query.value(0).toString());
01460 viewList << view;
01461 viewTextList << title;
01462 }
01463 }
01464 }
01465 else if (type == plStoredSearch)
01466 {
01467 MSqlQuery query(MSqlQuery::InitCon());
01468 query.prepare("SELECT rulename FROM customexample "
01469 "WHERE search > 0 ORDER BY rulename;");
01470 query.exec();
01471
01472 if (query.isActive() && query.size())
01473 {
01474 while (query.next())
01475 {
01476 QString rulename = query.value(0).toString();
01477 if (rulename <= " " || rulename == NULL)
01478 continue;
01479 rulename = QString::fromUtf8(query.value(0).toString());
01480 viewList << rulename;
01481 viewTextList << rulename;
01482 }
01483 }
01484 if (view != "")
01485 curView = viewList.findIndex(view);
01486 }
01487
01488 if (curView >= (int)viewList.count())
01489 curView = viewList.count() - 1;
01490 }
01491
01492 class plTitleSort
01493 {
01494 public:
01495 plTitleSort(void) {;}
01496
01497 bool operator()(const ProgramInfo *a, const ProgramInfo *b)
01498 {
01499 if (a->sortTitle != b->sortTitle)
01500 return (a->sortTitle < b->sortTitle);
01501
01502 if (a->recstatus == b->recstatus)
01503 return a->startts < b->startts;
01504
01505 if (a->recstatus == rsRecording) return true;
01506 if (b->recstatus == rsRecording) return false;
01507
01508 if (a->recstatus == rsWillRecord) return true;
01509 if (b->recstatus == rsWillRecord) return false;
01510
01511 return a->startts < b->startts;
01512 }
01513 };
01514
01515 class plTimeSort
01516 {
01517 public:
01518 plTimeSort(void) {;}
01519
01520 bool operator()(const ProgramInfo *a, const ProgramInfo *b)
01521 {
01522 if (a->startts == b->startts)
01523 return (a->chanid < b->chanid);
01524
01525 return (a->startts < b->startts);
01526 }
01527 };
01528
01529 void ProgLister::fillItemList(void)
01530 {
01531 if (curView < 0)
01532 return;
01533
01534 bool oneChanid = false;
01535 QString where = "";
01536 QString startstr = startTime.toString("yyyy-MM-ddThh:mm:50");
01537 QString qphrase = viewList[curView].utf8();
01538
01539 MSqlBindings bindings;
01540 bindings[":PGILSTART"] = startstr;
01541 bindings[":PGILPHRASE"] = qphrase;
01542 bindings[":PGILLIKEPHRASE"] = QString("%") + qphrase + "%";
01543
01544 if (type == plTitle)
01545 {
01546 where = "WHERE channel.visible = 1 "
01547 " AND program.endtime > :PGILSTART "
01548 " AND program.title = :PGILPHRASE ";
01549 }
01550 else if (type == plNewListings)
01551 {
01552 where = "LEFT JOIN oldprogram ON "
01553 " oldprogram.oldtitle = program.title "
01554 "WHERE channel.visible = 1 "
01555 " AND program.endtime > :PGILSTART "
01556 " AND oldprogram.oldtitle IS NULL "
01557 " AND program.manualid = 0 ";
01558
01559 if (qphrase == "premieres")
01560 {
01561 where += " AND ( ";
01562 where += " ( program.originalairdate=DATE(program.starttime) ";
01563 where += " AND (program.category = 'Special' ";
01564 where += " OR program.programid LIKE 'EP%0001')) ";
01565 where += " OR (program.category_type='movie' ";
01566 where += " AND program.stars > 0.5 ";
01567 where += " AND program.airdate >= YEAR(NOW()) - 2) ";
01568 where += " ) ";
01569 }
01570 else if (qphrase == "movies")
01571 {
01572 where += " AND program.category_type = 'movie' ";
01573 }
01574 else if (qphrase == "series")
01575 {
01576 where += " AND program.category_type = 'series' ";
01577 }
01578 else if (qphrase == "specials")
01579 {
01580 where += " AND program.category_type = 'tvshow' ";
01581 }
01582 else
01583 {
01584 where += " AND (program.category_type <> 'movie' ";
01585 where += " OR program.airdate >= YEAR(NOW()) - 3) ";
01586 }
01587 }
01588 else if (type == plTitleSearch)
01589 {
01590 where = "WHERE channel.visible = 1 "
01591 " AND program.endtime > :PGILSTART "
01592 " AND program.title LIKE :PGILLIKEPHRASE ";
01593 }
01594 else if (type == plKeywordSearch)
01595 {
01596 where = "WHERE channel.visible = 1 "
01597 " AND program.endtime > :PGILSTART "
01598 " AND (program.title LIKE :PGILLIKEPHRASE "
01599 " OR program.subtitle LIKE :PGILLIKEPHRASE "
01600 " OR program.description LIKE :PGILLIKEPHRASE ) ";
01601 }
01602 else if (type == plPeopleSearch)
01603 {
01604 where = ", people, credits WHERE channel.visible = 1 "
01605 " AND program.endtime > :PGILSTART "
01606 " AND people.name LIKE :PGILPHRASE "
01607 " AND credits.person = people.person "
01608 " AND program.chanid = credits.chanid "
01609 " AND program.starttime = credits.starttime";
01610 }
01611 else if (type == plPowerSearch)
01612 {
01613 QString powerWhere;
01614 MSqlBindings powerBindings;
01615
01616 bool genreflag = powerStringToSQL(qphrase, powerWhere, powerBindings);
01617
01618 if (powerWhere != "")
01619 {
01620 if (genreflag)
01621 where = QString("LEFT JOIN programgenres ON "
01622 "program.chanid = programgenres.chanid AND "
01623 "program.starttime = programgenres.starttime ");
01624
01625 where += QString("WHERE channel.visible = 1 "
01626 " AND program.endtime > :PGILSTART "
01627 " AND ( ") + powerWhere + " ) ";
01628 MSqlAddMoreBindings(bindings, powerBindings);
01629 }
01630 }
01631 else if (type == plSQLSearch)
01632 {
01633 qphrase.remove(QRegExp("^\\s*AND\\s+", false));
01634 where = QString("WHERE channel.visible = 1 "
01635 " AND program.endtime > :PGILSTART "
01636 " AND ( %1 ) ").arg(qphrase);
01637 if (addTables > "")
01638 where = addTables + " " + where;
01639 }
01640 else if (type == plChannel)
01641 {
01642 oneChanid = true;
01643 where = "WHERE channel.visible = 1 "
01644 " AND program.endtime > :PGILSTART "
01645 " AND channel.chanid = :PGILPHRASE ";
01646 }
01647 else if (type == plCategory)
01648 {
01649 if (!useGenres)
01650 {
01651 where = "WHERE channel.visible = 1 "
01652 " AND program.endtime > :PGILSTART "
01653 " AND program.category = :PGILPHRASE ";
01654 }
01655 else if (viewList[curView].find(":/:") < 0)
01656 {
01657 where = "JOIN programgenres g ON "
01658 " program.chanid = g.chanid AND "
01659 " program.starttime = g.starttime AND "
01660 " genre = :PGILPHRASE "
01661 "WHERE channel.visible = 1 "
01662 " AND program.endtime > :PGILSTART ";
01663 }
01664 else
01665 {
01666 where = "JOIN programgenres g1 ON "
01667 " program.chanid = g1.chanid AND "
01668 " program.starttime = g1.starttime AND "
01669 " g1.genre = :GENRE1 "
01670 "JOIN programgenres g2 ON "
01671 " program.chanid = g2.chanid AND "
01672 " program.starttime = g2.starttime AND "
01673 " g2.genre = :GENRE2 "
01674 "WHERE channel.visible = 1 "
01675 " AND program.endtime > :PGILSTART ";
01676 bindings[":GENRE1"] = viewList[curView].section(":/:", 0, 0);
01677 bindings[":GENRE2"] = viewList[curView].section(":/:", 1, 1);
01678 }
01679 }
01680 else if (type == plMovies)
01681 {
01682 where = "WHERE channel.visible = 1 "
01683 " AND program.endtime > :PGILSTART "
01684 " AND program.category_type = 'movie' "
01685 " AND program.stars "+qphrase+" ";
01686 }
01687 else if (type == plTime)
01688 {
01689 bindings[":PGILSEARCHTIME"] = searchTime.toString("yyyy-MM-dd hh:00:00");
01690 where = "WHERE channel.visible = 1 "
01691 " AND program.starttime >= :PGILSEARCHTIME ";
01692 if (titleSort)
01693 where += " AND program.starttime < DATE_ADD(:PGILSEARCHTIME, "
01694 "INTERVAL '1' HOUR) ";
01695 }
01696 else if (type == plRecordid)
01697 {
01698 where = "JOIN recordmatch ON "
01699 " (program.starttime = recordmatch.starttime "
01700 " AND program.chanid = recordmatch.chanid) "
01701 "WHERE channel.visible = 1 "
01702 " AND program.endtime > :PGILSTART "
01703 " AND recordmatch.recordid = :PGILPHRASE ";
01704 }
01705 else if (type == plStoredSearch)
01706 {
01707 QString fromc, wherec;
01708 MSqlQuery query(MSqlQuery::InitCon());
01709 query.prepare("SELECT fromclause, whereclause FROM customexample "
01710 "WHERE rulename = :RULENAME;");
01711 query.bindValue(":RULENAME", qphrase);
01712 query.exec();
01713
01714 if (query.isActive() && query.size())
01715 {
01716 query.next();
01717 fromc = query.value(0).toString();
01718 wherec = query.value(1).toString();
01719
01720 where = QString("WHERE channel.visible = 1 "
01721 " AND program.endtime > :PGILSTART "
01722 " AND ( %1 ) ").arg(wherec);
01723 if (fromc > "")
01724 where = fromc + " " + where;
01725 }
01726 }
01727
01728 schedList.FromScheduler();
01729 itemList.FromProgram(where, bindings, schedList, oneChanid);
01730
01731 ProgramInfo *s;
01732 vector<ProgramInfo *> sortedList;
01733
01734 while (itemList.count())
01735 {
01736 s = itemList.take();
01737 if (type == plTitle)
01738 s->sortTitle = s->subtitle;
01739 else
01740 s->sortTitle = s->title;
01741
01742 s->sortTitle.remove(QRegExp("^(The |A |An )"));
01743 sortedList.push_back(s);
01744 }
01745
01746 if (type == plNewListings || titleSort)
01747 {
01748
01749 sort(sortedList.begin(), sortedList.end(), plTitleSort());
01750
01751 QString curtitle = "";
01752 vector<ProgramInfo *>::iterator i = sortedList.begin();
01753 while (i != sortedList.end())
01754 {
01755 ProgramInfo *p = *i;
01756 if (p->sortTitle != curtitle)
01757 {
01758 curtitle = p->sortTitle;
01759 i++;
01760 }
01761 else
01762 {
01763 delete p;
01764 i = sortedList.erase(i);
01765 }
01766 }
01767 }
01768 if (!titleSort)
01769 sort(sortedList.begin(), sortedList.end(), plTimeSort());
01770
01771 if (reverseSort)
01772 {
01773 vector<ProgramInfo *>::reverse_iterator r = sortedList.rbegin();
01774 for (; r != sortedList.rend(); r++)
01775 itemList.append(*r);
01776 }
01777 else
01778 {
01779 vector<ProgramInfo *>::iterator i = sortedList.begin();
01780 for (; i != sortedList.end(); i++)
01781 itemList.append(*i);
01782 }
01783
01784 if (curItem < 0 && itemList.count() > 0)
01785 curItem = 0;
01786 else if (curItem >= (int)itemList.count())
01787 curItem = itemList.count() - 1;
01788 }
01789
01790 void ProgLister::updateView(QPainter *p)
01791 {
01792 QRect pr = viewRect;
01793 QPixmap pix(pr.size());
01794 pix.fill(this, pr.topLeft());
01795 QPainter tmp(&pix);
01796
01797 LayerSet *container = NULL;
01798
01799 container = theme->GetSet("view");
01800 if (container)
01801 {
01802 UITextType *uitype = (UITextType *)container->GetType("curview");
01803 if (uitype && curView >= 0)
01804 uitype->SetText(viewTextList[curView]);
01805
01806 container->Draw(&tmp, 4, 0);
01807 container->Draw(&tmp, 5, 0);
01808 container->Draw(&tmp, 6, 0);
01809 container->Draw(&tmp, 7, 0);
01810 container->Draw(&tmp, 8, 0);
01811 }
01812
01813 tmp.end();
01814 p->drawPixmap(pr.topLeft(), pix);
01815 }
01816
01817 void ProgLister::updateList(QPainter *p)
01818 {
01819 QRect pr = listRect;
01820 QPixmap pix(pr.size());
01821 pix.fill(this, pr.topLeft());
01822 QPainter tmp(&pix);
01823
01824 QString tmptitle;
01825
01826 LayerSet *container = theme->GetSet("selector");
01827 if (container)
01828 {
01829 UIListType *ltype = (UIListType *)container->GetType("proglist");
01830 if (ltype)
01831 {
01832 ltype->ResetList();
01833 ltype->SetActive(true);
01834
01835 QStringList starMap;
01836 QString starstr = "";
01837 for (int i = 0; i <= 4; i++)
01838 {
01839 starMap << starstr;
01840 starMap << starstr + "/";
01841 starstr += "*";
01842 }
01843
01844 int skip;
01845 if ((int)itemList.count() <= listsize || curItem <= listsize/2)
01846 skip = 0;
01847 else if (curItem >= (int)itemList.count() - listsize + listsize/2)
01848 skip = itemList.count() - listsize;
01849 else
01850 skip = curItem - listsize / 2;
01851 ltype->SetUpArrow(skip > 0);
01852 ltype->SetDownArrow(skip + listsize < (int)itemList.count());
01853
01854 int i;
01855 for (i = 0; i < listsize; i++)
01856 {
01857 if (i + skip >= (int)itemList.count())
01858 break;
01859
01860 ProgramInfo *pi = itemList.at(i+skip);
01861
01862 ltype->SetItemText(i, 1, pi->startts.toString(timeFormat));
01863 ltype->SetItemText(i, 2, pi->ChannelText(channelFormat));
01864
01865 if (pi->stars > 0.0)
01866 tmptitle = QString("%1 (%2, %3 )")
01867 .arg(pi->title).arg(pi->year)
01868 .arg(starMap[(int) (pi->stars * 8)]);
01869 else if (pi->subtitle == "")
01870 tmptitle = pi->title;
01871 else
01872 {
01873 if (type == plTitle)
01874 tmptitle = pi->subtitle;
01875 else
01876 tmptitle = QString("%1 - \"%2\"")
01877 .arg(pi->title)
01878 .arg(pi->subtitle);
01879 }
01880
01881 ltype->SetItemText(i, 3, tmptitle);
01882 ltype->SetItemText(i, 4, pi->RecStatusChar());
01883
01884 if (pi->recstatus == rsConflict ||
01885 pi->recstatus == rsOffLine)
01886 ltype->EnableForcedFont(i, "conflicting");
01887 else if (pi->recstatus == rsRecording)
01888 ltype->EnableForcedFont(i, "recording");
01889 else if (pi->recstatus == rsWillRecord)
01890 ltype->EnableForcedFont(i, "record");
01891
01892 if (i + skip == curItem)
01893 ltype->SetItemCurrent(i);
01894 }
01895 }
01896 }
01897
01898 if (itemList.count() == 0)
01899 container = theme->GetSet("noprograms_list");
01900
01901 if (container)
01902 {
01903 container->Draw(&tmp, 0, 0);
01904 container->Draw(&tmp, 1, 0);
01905 container->Draw(&tmp, 2, 0);
01906 container->Draw(&tmp, 3, 0);
01907 container->Draw(&tmp, 4, 0);
01908 container->Draw(&tmp, 5, 0);
01909 container->Draw(&tmp, 6, 0);
01910 container->Draw(&tmp, 7, 0);
01911 container->Draw(&tmp, 8, 0);
01912 }
01913
01914 tmp.end();
01915 p->drawPixmap(pr.topLeft(), pix);
01916 }
01917
01918 void ProgLister::updateInfo(QPainter *p)
01919 {
01920 QRect pr = infoRect;
01921 QPixmap pix(pr.size());
01922 pix.fill(this, pr.topLeft());
01923 QPainter tmp(&pix);
01924
01925 LayerSet *container = NULL;
01926 ProgramInfo *pi = itemList.at(curItem);
01927
01928 if (pi)
01929 {
01930 container = theme->GetSet("program_info");
01931 if (container)
01932 {
01933 QMap<QString, QString> infoMap;
01934 pi->ToMap(infoMap);
01935 container->ClearAllText();
01936 container->SetText(infoMap);
01937 }
01938 }
01939 else
01940 container = theme->GetSet("norecordings_info");
01941
01942 if (container)
01943 {
01944 container->Draw(&tmp, 4, 0);
01945 container->Draw(&tmp, 5, 0);
01946 container->Draw(&tmp, 6, 0);
01947 container->Draw(&tmp, 7, 0);
01948 container->Draw(&tmp, 8, 0);
01949 }
01950
01951 tmp.end();
01952 p->drawPixmap(pr.topLeft(), pix);
01953 }
01954
01955 void ProgLister::customEvent(QCustomEvent *e)
01956 {
01957 if ((MythEvent::Type)(e->type()) != MythEvent::MythEventMessage)
01958 return;
01959
01960 MythEvent *me = (MythEvent *)e;
01961 QString message = me->Message();
01962 if (message != "SCHEDULE_CHANGE" && message != "CHOOSE_VIEW")
01963 return;
01964
01965 if (message == "CHOOSE_VIEW")
01966 {
01967 chooseView();
01968 if (curView < 0)
01969 {
01970 reject();
01971 return;
01972 }
01973 }
01974
01975 refillAll = true;
01976
01977 if (!allowEvents)
01978 return;
01979
01980 allowEvents = false;
01981
01982 allowUpdates = false;
01983 do
01984 {
01985 refillAll = false;
01986 fillItemList();
01987 } while (refillAll);
01988 allowUpdates = true;
01989 update(fullRect);
01990
01991 allowEvents = true;
01992 }
01993