MythTV  0.26-pre
progfind.cpp
Go to the documentation of this file.
00001 // Qt
00002 #include <QDateTime>
00003 #include <QCoreApplication>
00004 #include <QStringList>
00005 #include <QRegExp>
00006 #include <QKeyEvent>
00007 #include <QEvent>
00008 
00009 // MythTV
00010 #include "mythdb.h"
00011 #include "mythdbcon.h"
00012 #include "mythdirs.h"
00013 #include "mythcorecontext.h"
00014 #include "recordinginfo.h"
00015 #include "tv.h"
00016 
00017 // MythUI
00018 #include "mythuitext.h"
00019 #include "mythuibuttonlist.h"
00020 #include "mythuibutton.h"
00021 #include "mythuihelper.h"
00022 #include "mythscreenstack.h"
00023 #include "mythmainwindow.h"
00024 
00025 // mythfrontend
00026 #include "guidegrid.h"
00027 #include "customedit.h"
00028 #include "progfind.h"
00029 
00030 #define LOC      QString("ProgFinder: ")
00031 #define LOC_ERR  QString("ProgFinder, Error: ")
00032 #define LOC_WARN QString("ProgFinder, Warning: ")
00033 
00034 void RunProgramFinder(TV *player, bool embedVideo, bool allowEPG)
00035 {
00036     // Language specific progfinder, if needed
00037     MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
00038     ProgFinder *programFind = NULL;
00039     if (gCoreContext->GetLanguage() == "ja")
00040         programFind = new JaProgFinder(mainStack, allowEPG, player, embedVideo);
00041     else if (gCoreContext->GetLanguage() == "he")
00042         programFind = new HeProgFinder(mainStack, allowEPG, player, embedVideo);
00043     else if (gCoreContext->GetLanguage() == "ru")
00044         programFind = new RuProgFinder(mainStack, allowEPG, player, embedVideo);
00045     else // default
00046         programFind = new ProgFinder(mainStack, allowEPG, player, embedVideo);
00047 
00048     if (programFind->Create())
00049         mainStack->AddScreen(programFind, (player == NULL));
00050     else
00051         delete programFind;
00052 }
00053 
00054 ProgFinder::ProgFinder(MythScreenStack *parentStack, bool allowEPG,
00055                        TV *player, bool embedVideo)
00056           : ScheduleCommon(parentStack, "ProgFinder"),
00057     m_currentLetter(""),
00058     m_player(player),            m_embedVideo(embedVideo),
00059     m_allowEPG(allowEPG),        m_allowKeypress(true),
00060     m_alphabetList(NULL),        m_showList(NULL),
00061     m_timesList(NULL),           m_searchText(NULL),
00062     m_help1Text(NULL),           m_help2Text(NULL)
00063 {
00064 }
00065 
00066 bool ProgFinder::Create()
00067 {
00068     if (!LoadWindowFromXML("schedule-ui.xml", "programfind", this))
00069         return false;
00070 
00071     bool err = false;
00072     UIUtilE::Assign(this, m_alphabetList, "alphabet", &err);
00073     UIUtilE::Assign(this, m_showList, "shows", &err);
00074     UIUtilE::Assign(this, m_timesList, "times", &err);
00075 
00076     UIUtilW::Assign(this, m_help1Text, "help1text");
00077     UIUtilW::Assign(this, m_help2Text, "help2text");
00078     UIUtilW::Assign(this, m_searchText, "search");
00079 
00080     if (err)
00081     {
00082         LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'programfind'");
00083         return false;
00084     }
00085 
00086     m_alphabetList->SetLCDTitles(tr("Starts With"), "");
00087     m_showList->SetLCDTitles(tr("Programs"), "");
00088     m_timesList->SetLCDTitles(tr("Times"), "buttontext");
00089 
00090     BuildFocusList();
00091     LoadInBackground();
00092 
00093     if (m_player)
00094         m_player->StartEmbedding(QRect());
00095 
00096     return true;
00097 }
00098 
00099 void ProgFinder::Init(void)
00100 {
00101     m_allowKeypress = true;
00102 
00103     initAlphabetList();
00104 
00105     gCoreContext->addListener(this);
00106 
00107     connect(m_timesList, SIGNAL(itemSelected(MythUIButtonListItem*)),
00108             SLOT(updateInfo()));
00109     connect(m_timesList, SIGNAL(itemClicked(MythUIButtonListItem*)),
00110             SLOT(select()));
00111     connect(m_timesList, SIGNAL(LosingFocus()), SLOT(timesListLosingFocus()));
00112     connect(m_timesList, SIGNAL(TakingFocus()), SLOT(timesListTakeFocus()));
00113 
00114     connect(m_alphabetList, SIGNAL(itemSelected(MythUIButtonListItem*)),
00115             SLOT(alphabetListItemSelected(MythUIButtonListItem*)));
00116     connect(m_alphabetList, SIGNAL(itemClicked(MythUIButtonListItem*)),
00117             SLOT(select()));
00118 
00119     connect(m_showList, SIGNAL(TakingFocus()), SLOT(showListTakeFocus()));
00120     connect(m_showList, SIGNAL(itemClicked(MythUIButtonListItem*)),
00121             SLOT(select()));
00122 
00123     m_alphabetList->MoveToNamedPosition("A");
00124 }
00125 
00126 ProgFinder::~ProgFinder()
00127 {
00128     gCoreContext->removeListener(this);
00129 
00130     // if we have a player and we are returning to it we need
00131     // to tell it to stop embedding and return to fullscreen
00132     if (m_player && m_allowEPG)
00133     {
00134         QString message = QString("PROGFINDER_EXITING");
00135         qApp->postEvent(m_player, new MythEvent(message));
00136     }
00137 }
00138 
00139 void ProgFinder::alphabetListItemSelected(MythUIButtonListItem *item)
00140 {
00141     if (!item || (m_currentLetter == item->GetText()))
00142         return;
00143 
00144     m_currentLetter = item->GetText();
00145 
00146     updateShowList();
00147     updateInfo();
00148 }
00149 
00150 void ProgFinder::timesListLosingFocus(void)
00151 {
00152     m_timesList->Reset();
00153 }
00154 
00155 void ProgFinder::showListTakeFocus(void)
00156 {
00157     updateInfo();
00158 }
00159 
00160 void ProgFinder::timesListTakeFocus(void)
00161 {
00162     selectShowData("", 0);
00163     updateInfo();
00164 }
00165 
00166 bool ProgFinder::keyPressEvent(QKeyEvent *event)
00167 {
00168     if (!m_allowKeypress)
00169         return true;
00170 
00171     m_allowKeypress = false;
00172 
00173     if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
00174     {
00175         m_allowKeypress = true;
00176         return true;
00177     }
00178 
00179     bool handled = false;
00180 
00181     QStringList actions;
00182     handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend", event, actions);
00183 
00184     for (int i = 0; i < actions.size() && !handled; ++i)
00185     {
00186         QString action = actions[i];
00187         handled = true;
00188 
00189         if (action == "EDIT")
00190             edit();
00191         else if (action == "CUSTOMEDIT")
00192             customEdit();
00193         else if (action == "UPCOMING")
00194             upcoming();
00195         else if (action == "DETAILS" || action == "INFO")
00196             details();
00197         else if (action == "TOGGLERECORD")
00198             quickRecord();
00199         else if (action == "GUIDE" || action == "4")
00200             showGuide();
00201         else if (action == "ESCAPE")
00202         {
00203             // don't fade the screen if we are returning to the player
00204             if (m_player && m_allowEPG)
00205                 GetScreenStack()->PopScreen(this, false);
00206             else
00207                 GetScreenStack()->PopScreen(this, true);
00208         }
00209         else
00210             handled = false;
00211     }
00212 
00213     if (!handled && MythScreenType::keyPressEvent(event))
00214         handled = true;
00215 
00216     m_allowKeypress = true;
00217 
00218     return handled;
00219 }
00220 
00221 void ProgFinder::ShowMenu(void)
00222 {
00223     QString label = tr("Options");
00224 
00225     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00226     MythDialogBox *menuPopup = new MythDialogBox(label, popupStack, "menuPopup");
00227 
00228     if (menuPopup->Create())
00229     {
00230         menuPopup->SetReturnEvent(this, "menu");
00231 
00232         if (!m_searchStr.isEmpty())
00233             menuPopup->AddButton(tr("Clear Search"));
00234         menuPopup->AddButton(tr("Edit Search"));
00235         if (GetFocusWidget() == m_timesList && m_timesList->GetCount() > 0)
00236         {
00237             menuPopup->AddButton(tr("Toggle Record"));
00238             menuPopup->AddButton(tr("Program Details"));
00239             menuPopup->AddButton(tr("Upcoming"));
00240             menuPopup->AddButton(tr("Custom Edit"));
00241             menuPopup->AddButton(tr("Program Guide"));
00242         }
00243 
00244         popupStack->AddScreen(menuPopup);
00245     }
00246     else
00247     {
00248         delete menuPopup;
00249     }
00250 }
00251 
00252 void ProgFinder::customEvent(QEvent *event)
00253 {
00254     if ((MythEvent::Type)(event->type()) == MythEvent::MythEventMessage)
00255     {
00256         MythEvent *me = (MythEvent *)event;
00257         QString message = me->Message();
00258 
00259         if (message == "SCHEDULE_CHANGE")
00260         {
00261             if (GetFocusWidget() == m_timesList)
00262             {
00263                 ProgramInfo *curPick = m_showData[m_timesList->GetCurrentPos()];
00264                 if (curPick)
00265                     selectShowData(curPick->GetTitle(),
00266                                    m_timesList->GetCurrentPos());
00267             }
00268         }
00269     }
00270     else if (event->type() == DialogCompletionEvent::kEventType)
00271     {
00272         DialogCompletionEvent *dce = (DialogCompletionEvent*)(event);
00273 
00274         QString resultid   = dce->GetId();
00275         QString resulttext = dce->GetResultText();
00276 
00277         if (resultid == "menu")
00278         {
00279             if (resulttext == tr("Clear Search"))
00280             {
00281                 m_searchStr.clear();
00282                 if (m_searchText)
00283                     m_searchText->SetText(m_searchStr);
00284                 updateShowList();
00285                 SetFocusWidget(m_showList);
00286             }
00287             else if (resulttext == tr("Edit Search"))
00288             {
00289                 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00290                 SearchInputDialog *textInput =
00291                         new SearchInputDialog(popupStack, m_searchStr);
00292 
00293                 if (textInput->Create())
00294                 {
00295                     textInput->SetReturnEvent(this, "searchtext");
00296                     popupStack->AddScreen(textInput);
00297                 }
00298             }
00299             else if (resulttext == tr("Toggle Record"))
00300             {
00301                 quickRecord();
00302             }
00303             else if (resulttext == tr("Program Details"))
00304             {
00305                 details();
00306             }
00307             else if (resulttext == tr("Upcoming"))
00308             {
00309                 upcoming();
00310             }
00311             else if (resulttext == tr("Custom Edit"))
00312             {
00313                 customEdit();
00314             }
00315             else if (resulttext == tr("Program Guide"))
00316             {
00317                 showGuide();
00318             }
00319         }
00320         else if (resultid == "searchtext")
00321         {
00322             m_searchStr = resulttext;
00323             if (m_searchText)
00324                 m_searchText->SetText(m_searchStr);
00325             updateShowList();
00326             SetFocusWidget(m_showList);
00327         }
00328         else
00329             ScheduleCommon::customEvent(event);
00330     }
00331 }
00332 
00333 void ProgFinder::updateInfo(void)
00334 {
00335     if (m_help1Text)
00336         m_help1Text->Reset();
00337     if (m_help2Text)
00338         m_help2Text->Reset();
00339 
00340     if (GetFocusWidget() == m_alphabetList)
00341     {
00342         QString title;
00343         QString description;
00344 
00345         if (m_showList->GetCount() == 0)
00346         {
00347             if (m_help1Text)
00348                 m_help1Text->SetText(tr("No Programs"));
00349             if (m_help2Text)
00350                 m_help2Text->SetText(tr("There are no available programs under this search. "
00351                                         "Please select another search."));
00352         }
00353         else
00354         {
00355             if (m_help1Text)
00356                 m_help1Text->SetText(tr("Select a letter..."));
00357             if (m_help2Text)
00358                 m_help2Text->SetText(tr("Pick the first letter of the program name, "
00359                                         "then press SELECT or the right arrow."));
00360         }
00361 
00362         ResetMap(m_infoMap);
00363     }
00364     else if (GetFocusWidget() == m_showList)
00365     {
00366         if (m_help1Text)
00367             m_help1Text->SetText(tr("Select a program..."));
00368         if (m_help2Text)
00369             m_help2Text->SetText(tr("Select the title of the program you wish to find. "
00370                                     "When finished return with the left arrow key. "
00371                                     "Press SELECT to schedule a recording."));
00372 
00373         ResetMap(m_infoMap);
00374     }
00375     else if (GetFocusWidget() == m_timesList)
00376     {
00377         if (m_showData.size() == 0)
00378         {
00379             ResetMap(m_infoMap);
00380             if (m_help1Text)
00381                 m_help1Text->SetText(tr("No Programs"));
00382             if (m_help2Text)
00383                 m_help2Text->SetText(tr("There are no available programs under "
00384                                         "this search. Please select another "
00385                                         "search."));
00386         }
00387         else
00388         {
00389             InfoMap infoMap;
00390             m_showData[m_timesList->GetCurrentPos()]->ToMap(infoMap);
00391             SetTextFromMap(infoMap);
00392             m_infoMap = infoMap;
00393         }
00394     }
00395 }
00396 
00397 void ProgFinder::showGuide()
00398 {
00399     if (m_allowEPG)
00400     {
00401         QString startchannel = gCoreContext->GetSetting("DefaultTVChannel");
00402         if (startchannel.isEmpty())
00403             startchannel = '3';
00404         uint startchanid = 0;
00405         GuideGrid::RunProgramGuide(startchanid, startchannel, m_player, m_embedVideo, false, -2);
00406     }
00407 }
00408 
00409 void ProgFinder::getInfo(bool toggle)
00410 {
00411     if (GetFocusWidget() == m_timesList)
00412     {
00413         ProgramInfo *curPick = m_showData[m_timesList->GetCurrentPos()];
00414 
00415         if (curPick)
00416         {
00417             if (toggle)
00418             {
00419                 RecordingInfo ri(*curPick);
00420                 ri.ToggleRecord();
00421                 *curPick = ri;
00422             }
00423             else
00424                 EditRecording(curPick);
00425         }
00426         else
00427             return;
00428 
00429         // TODO: When schedule editor is non-blocking, move
00430         selectShowData(curPick->GetTitle(), m_timesList->GetCurrentPos());
00431     }
00432 }
00433 
00434 void ProgFinder::edit()
00435 {
00436     if (GetFocusWidget() == m_timesList)
00437     {
00438         ProgramInfo *curPick = m_showData[m_timesList->GetCurrentPos()];
00439 
00440         if (curPick)
00441         {
00442             EditScheduled(curPick);
00443             // TODO: When schedule editor is non-blocking, move
00444             selectShowData(curPick->GetTitle(), m_timesList->GetCurrentPos());
00445         }
00446     }
00447 }
00448 
00449 void ProgFinder::select()
00450 {
00451     if (GetFocusWidget() == m_timesList)
00452         getInfo();
00453     else if (GetFocusWidget() == m_alphabetList && m_showList->GetCount())
00454         SetFocusWidget(m_showList);
00455     else if (GetFocusWidget() == m_showList)
00456         SetFocusWidget(m_timesList);
00457 }
00458 
00459 void ProgFinder::customEdit()
00460 {
00461     if (GetFocusWidget() == m_timesList)
00462     {
00463         ProgramInfo *pginfo = m_showData[m_timesList->GetCurrentPos()];
00464         EditCustom(pginfo);
00465     }
00466 }
00467 
00468 void ProgFinder::upcoming()
00469 {
00470     if (GetFocusWidget() == m_timesList)
00471     {
00472         ProgramInfo *pginfo = m_showData[m_timesList->GetCurrentPos()];
00473         ShowUpcoming(pginfo);
00474     }
00475 }
00476 
00477 void ProgFinder::details()
00478 {
00479     if (GetFocusWidget() != m_timesList)
00480         return;
00481 
00482     ProgramInfo *curPick = m_showData[m_timesList->GetCurrentPos()];
00483     ShowDetails(curPick);
00484 }
00485 
00486 void ProgFinder::quickRecord()
00487 {
00488     getInfo(true);
00489 }
00490 
00491 void ProgFinder::updateTimesList()
00492 {
00493     InfoMap infoMap;
00494 
00495     m_timesList->Reset();
00496 
00497     if (m_showData.size() > 0)
00498     {
00499         QString itemText;
00500         QDateTime starttime;
00501         for (uint i = 0; i < m_showData.size(); ++i)
00502         {
00503             starttime = m_showData[i]->GetScheduledStartTime();
00504             itemText = MythDateTimeToString(starttime,
00505                                             kDateTimeFull | kSimplify);
00506 
00507             MythUIButtonListItem *item =
00508                 new MythUIButtonListItem(m_timesList, "");
00509 
00510             m_showData[i]->ToMap(infoMap);
00511             item->SetTextFromMap(infoMap);
00512 
00513             QString state = toUIState(m_showData[i]->GetRecordingStatus());
00514             item->SetText(itemText, "buttontext", state);
00515             item->DisplayState(state, "status");
00516         }
00517     }
00518 }
00519 
00520 void ProgFinder::getShowNames()
00521 {
00522     m_showNames.clear();
00523 
00524     QString thequery;
00525     MSqlBindings bindings;
00526 
00527     MSqlQuery query(MSqlQuery::InitCon());
00528     whereClauseGetSearchData(thequery, bindings);
00529 
00530     query.prepare(thequery);
00531     query.bindValues(bindings);
00532     if (!query.exec())
00533     {
00534         MythDB::DBError("getShowNames", query);
00535         return;
00536     }
00537 
00538     QString data;
00539     while (query.next())
00540     {
00541         data = query.value(0).toString();
00542 
00543         if (formatSelectedData(data))
00544             m_showNames[data.toLower()] = data;
00545     }
00546 }
00547 
00548 void ProgFinder::updateShowList()
00549 {
00550     m_showList->Reset();
00551 
00552     if (m_showNames.isEmpty())
00553         getShowNames();
00554 
00555     ShowName::Iterator it;
00556     for (it = m_showNames.begin(); it != m_showNames.end(); ++it)
00557     {
00558         QString tmpProgData = *it;
00559         restoreSelectedData(tmpProgData);
00560         new MythUIButtonListItem(m_showList, tmpProgData);
00561     }
00562 
00563     m_showNames.clear();
00564 }
00565 
00566 void ProgFinder::selectShowData(QString progTitle, int newCurShow)
00567 {
00568     progTitle = m_showList->GetValue();
00569 
00570     QDateTime progStart = QDateTime::currentDateTime();
00571 
00572     MSqlBindings bindings;
00573     QString querystr = "WHERE program.title = :TITLE "
00574                        "  AND program.endtime > :ENDTIME "
00575                        "  AND channel.visible = 1 ";
00576     bindings[":TITLE"] = progTitle;
00577     bindings[":ENDTIME"] = progStart.addSecs(50 - progStart.time().second());
00578 
00579     LoadFromScheduler(m_schedList);
00580     LoadFromProgram(m_showData, querystr, bindings, m_schedList);
00581 
00582     updateTimesList();
00583 
00584     m_timesList->SetItemCurrent(newCurShow);
00585 }
00586 
00587 void ProgFinder::initAlphabetList(void)
00588 {
00589     for (int charNum = 48; charNum < 91; ++charNum)
00590     {
00591         if (charNum == 58)
00592             charNum = 65;
00593 
00594         new MythUIButtonListItem(m_alphabetList, QString((char)charNum));
00595     }
00596 
00597     new MythUIButtonListItem(m_alphabetList, QString('@'));
00598 }
00599 
00600 void ProgFinder::whereClauseGetSearchData(QString &where, MSqlBindings &bindings)
00601 {
00602     QDateTime progStart = QDateTime::currentDateTime();
00603     QString searchChar = m_alphabetList->GetValue();
00604 
00605     if (searchChar.isEmpty())
00606         searchChar = "A";
00607 
00608     if (searchChar.contains('@'))
00609     {
00610         where = "SELECT DISTINCT title FROM program "
00611                 "LEFT JOIN channel ON program.chanid = channel.chanid "
00612                 "WHERE channel.visible = 1 AND "
00613                 "( title NOT REGEXP '^[A-Z0-9]' AND "
00614                 "  title NOT REGEXP '^The [A-Z0-9]' AND "
00615                 "  title NOT REGEXP '^A [A-Z0-9]' AND "
00616                 "  title NOT REGEXP '^An [A-Z0-9]' AND "
00617                 "  starttime > :STARTTIME ) ";
00618         if (!m_searchStr.isEmpty())
00619         {
00620             where += "AND title LIKE :SEARCH ";
00621             bindings[":SEARCH"] = '%' + m_searchStr + '%';
00622         }
00623 
00624         where += "ORDER BY title;";
00625 
00626         bindings[":STARTTIME"] =
00627             progStart.addSecs(50 - progStart.time().second());
00628     }
00629     else
00630     {
00631         QString one = searchChar + '%';
00632         QString two = QString("The ") + one;
00633         QString three = QString("A ") + one;
00634         QString four = QString("An ") + one;
00635 
00636         where = "SELECT DISTINCT title FROM program "
00637                 "LEFT JOIN channel ON program.chanid = channel.chanid "
00638                 "WHERE channel.visible = 1 "
00639                 "AND ( title LIKE :ONE OR title LIKE :TWO "
00640                 "      OR title LIKE :THREE "
00641                 "      OR title LIKE :FOUR ) "
00642                 "AND starttime > :STARTTIME ";
00643         if (!m_searchStr.isEmpty())
00644             where += "AND title LIKE :SEARCH ";
00645 
00646         where += "ORDER BY title;";
00647 
00648         bindings[":ONE"] = one;
00649         bindings[":TWO"] = two;
00650         bindings[":THREE"] = three;
00651         bindings[":FOUR"] = four;
00652         bindings[":STARTTIME"] =
00653             progStart.addSecs(50 - progStart.time().second());
00654 
00655         if (!m_searchStr.isEmpty())
00656             bindings[":SEARCH"] = '%' + m_searchStr + '%';
00657     }
00658 }
00659 
00660 bool ProgFinder::formatSelectedData(QString& data)
00661 {
00662     bool retval = true;
00663     QString searchChar = m_alphabetList->GetValue();
00664 
00665     if (searchChar == "T")
00666     {
00667         if (data.left(4) != "The " && data.left(2) != "A ")
00668         {
00669              // nothing, use as is
00670         }
00671         else if (data.left(5) == "The T")
00672             data = data.mid(4) + ", The";
00673         else if (data.left(3) == "A T")
00674             data = data.mid(2) + ", A";
00675         else
00676         {
00677             // don't add
00678             retval = false;
00679         }
00680     }
00681     else if (searchChar == "A")
00682     {
00683         if (data.left(4) != "The " && data.left(2) != "A ")
00684         {
00685              // nothing, use as is
00686         }
00687         else if (data.left(5) == "The A")
00688             data = data.mid(4) + ", The";
00689         else if (data.left(3) == "A A")
00690              data = data.mid(2) + ", A";
00691         else if (data.left(4) == "An A")
00692              data = data.mid(3) + ", An";
00693         else
00694         {
00695             // don't add
00696             retval = false;
00697         }
00698     }
00699     else
00700     {
00701         if (data.left(4) == "The ")
00702             data = data.mid(4) + ", The";
00703         else if (data.left(2) == "A ")
00704             data = data.mid(2) + ", A";
00705         else if (data.left(3) == "An ")
00706             data = data.mid(3) + ", An";
00707     }
00708 
00709     return retval;
00710 }
00711 
00712 bool ProgFinder::formatSelectedData(QString& data, int charNum)
00713 {
00714     bool retval = true;
00715 
00716     if (charNum == 29 || charNum == 10)
00717     {
00718         if (data.left(5) == "The T" && charNum == 29)
00719             data = data.mid(4) + ", The";
00720         else if (data.left(5) == "The A" && charNum == 10)
00721             data = data.mid(4) + ", The";
00722         else if (data.left(3) == "A T" && charNum == 29)
00723             data = data.mid(2) + ", A";
00724         else if (data.left(3) == "A A" && charNum == 10)
00725             data = data.mid(2) + ", A";
00726         else if (data.left(4) == "An A" && charNum == 10)
00727              data = data.mid(3) + ", An";
00728         else if (data.left(4) != "The " && data.left(2) != "A ")
00729         {
00730             // use as is
00731         }
00732         else
00733         {
00734             // don't add
00735             retval = false;
00736         }
00737     }
00738     else
00739     {
00740         if (data.left(4) == "The ")
00741             data = data.mid(4) + ", The";
00742         if (data.left(2) == "A ")
00743             data = data.mid(2) + ", A";
00744         if (data.left(3) == "An ")
00745             data = data.mid(3) + ", An";
00746     }
00747 
00748     return retval;
00749 }
00750 
00751 void ProgFinder::restoreSelectedData(QString &data)
00752 {
00753     if (data.right(5) == ", The")
00754         data = "The " + data.left(data.length() - 5);
00755     if (data.right(3) == ", A")
00756         data = "A " + data.left(data.length() - 3);
00757 }
00758 
00760 // Japanese specific program finder
00761 
00762 // japanese HIRAGANA list and more
00763 const char* JaProgFinder::searchChars[] = {
00764     "あ", "か", "さ", "た", "な", "は", "ま", "や", "ら", "わ",
00765     "英", "数",
00766     0,
00767 };
00768 
00769 JaProgFinder::JaProgFinder(MythScreenStack *parentStack, bool gg,
00770                            TV *player, bool embedVideo)
00771             : ProgFinder(parentStack, gg, player, embedVideo)
00772 {
00773     for (numberOfSearchChars = 0; searchChars[numberOfSearchChars];
00774          ++numberOfSearchChars)
00775          ;
00776 }
00777 
00778 void JaProgFinder::initAlphabetList()
00779 {
00780     for (int charNum = 0; charNum < numberOfSearchChars; ++charNum)
00781     {
00782         new MythUIButtonListItem(m_alphabetList, QString(searchChars[charNum]));
00783     }
00784 }
00785 
00786 // search title_pronounce
00787 // we hope japanese HIRAGANA and alphabets, numerics is inserted
00788 // these character must required ZENKAKU
00789 // because query work not fine, if mysql's default charset latin1
00790 void JaProgFinder::whereClauseGetSearchData(QString &where, MSqlBindings &bindings)
00791 {
00792     QDateTime progStart = QDateTime::currentDateTime();
00793     int charNum = m_alphabetList->GetCurrentPos();
00794 
00795     where = "SELECT DISTINCT title FROM program "
00796             "LEFT JOIN channel ON program.chanid = channel.chanid "
00797             "WHERE channel.visible = 1 ";
00798 
00799     switch (charNum) {
00800     case 0:
00801         where += "AND ( title_pronounce >= 'あ' AND title_pronounce <= 'お') ";
00802         break;
00803     case 1:
00804         where += "AND ( title_pronounce >= 'か' AND title_pronounce <= 'ご') ";
00805         break;
00806     case 2:
00807         where += "AND ( title_pronounce >= 'さ' AND title_pronounce <= 'そ') ";
00808         break;
00809     case 3:
00810         where += "AND ( title_pronounce >= 'た' AND title_pronounce <= 'ど') ";
00811         break;
00812     case 4:
00813         where += "AND ( title_pronounce >= 'な' AND title_pronounce <= 'の') ";
00814         break;
00815     case 5:
00816         where += "AND ( title_pronounce >= 'は' AND title_pronounce <= 'ぽ') ";
00817         break;
00818     case 6:
00819         where += "AND ( title_pronounce >= 'ま' AND title_pronounce <= 'も') ";
00820         break;
00821     case 7:
00822         where += "AND ( title_pronounce >= 'や' AND title_pronounce <= 'よ') ";
00823         break;
00824     case 8:
00825         where += "AND ( title_pronounce >= 'ら' AND title_pronounce <= 'ろ') ";
00826         break;
00827     case 9:
00828         where += "AND ( title_pronounce >= 'わ' AND title_pronounce <= 'ん') ";
00829         break;
00830     case 10:
00831         where += "AND ( title_pronounce >= 'A' AND title_pronounce <= 'z') ";
00832         break;
00833     case 11:
00834         where += "AND ( title_pronounce >= '0' AND title_pronounce <= '9') ";
00835         break;
00836     }
00837 
00838     where += "AND starttime > :STARTTIME ";
00839 
00840     if (!m_searchStr.isEmpty())
00841     {
00842         where += "AND title_pronounce LIKE :SEARCH ";
00843         bindings[":SEARCH"] = '%' + m_searchStr + '%';
00844     }
00845 
00846     where += "ORDER BY title_pronounce;";
00847 
00848     bindings[":STARTTIME"] = progStart.addSecs(50 - progStart.time().second());
00849 }
00850 
00851 
00852 bool JaProgFinder::formatSelectedData(QString& data)
00853 {
00854     (void)data;
00855     return true;
00856 }
00857 
00858 bool JaProgFinder::formatSelectedData(QString& data, int charNum)
00859 {
00860     (void)data;
00861     (void)charNum;
00862     return true;
00863 }
00864 
00865 void JaProgFinder::restoreSelectedData(QString& data)
00866 {
00867     (void)data;
00868 }
00869 
00870 // Hebrew specific program finder
00871 
00872 // Hebrew alphabet list and more
00873 const char* HeProgFinder::searchChars[] = {
00874     "\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", "\u05d6", "\u05d7", "\u05d8",
00875     "\u05d9", "\u05db", "\u05dc", "\u05de", "\u05e0", "\u05e1", "\u05e2", "\u05e4", "\u05e6",
00876     "\u05e7", "\u05e8", "\u05e9", "\u05ea", "E", "#", 0 };
00877 
00878 HeProgFinder::HeProgFinder(MythScreenStack *parentStack, bool gg,
00879                            TV *player, bool embedVideo)
00880             : ProgFinder(parentStack, gg, player, embedVideo)
00881 {
00882     for (numberOfSearchChars = 0; searchChars[numberOfSearchChars];
00883          ++numberOfSearchChars)
00884         ;
00885 }
00886 
00887 void HeProgFinder::initAlphabetList()
00888 {
00889     for (int charNum = 0; charNum < numberOfSearchChars; ++charNum)
00890     {
00891         new MythUIButtonListItem(m_alphabetList, QString::fromUtf8(searchChars[charNum]));
00892     }
00893 }
00894 
00895 // search by hebrew aleph-bet
00896 // # for all numbers, E for all latin
00897 void HeProgFinder::whereClauseGetSearchData(QString &where, MSqlBindings &bindings)
00898 {
00899     QDateTime progStart = QDateTime::currentDateTime();
00900     QString searchChar = m_alphabetList->GetValue();
00901 
00902     if (searchChar.isEmpty())
00903         searchChar = searchChars[0];
00904 
00905     where = "SELECT DISTINCT title FROM program "
00906             "LEFT JOIN channel ON program.chanid = channel.chanid "
00907             "WHERE channel.visible = 1 ";
00908 
00909     if (searchChar.contains('E'))
00910     {
00911         where += "AND ( title REGEXP '^[A-Z]') ";
00912     }
00913     else if (searchChar.contains('#'))
00914     {
00915         where += "AND ( title REGEXP '^[0-9]') ";
00916     }
00917     else
00918     {
00919         QString one = searchChar + '%';
00920         bindings[":ONE"] = one;
00921         where += "AND ( title LIKE :ONE ) ";
00922     }
00923 
00924     where += "AND starttime > :STARTTIME ";
00925 
00926     if (!m_searchStr.isEmpty())
00927     {
00928         where += "AND title LIKE :SEARCH ";
00929         bindings[":SEARCH"] = '%' + m_searchStr + '%';
00930     }
00931 
00932     where += "ORDER BY title;";
00933 
00934     bindings[":STARTTIME"] = progStart.addSecs(50 - progStart.time().second());
00935 }
00936 
00937 bool HeProgFinder::formatSelectedData(QString& data)
00938 {
00939     (void)data;
00940     return true;
00941 }
00942 
00943 bool HeProgFinder::formatSelectedData(QString& data, int charNum)
00944 {
00945     (void)data;
00946     (void)charNum;
00947     return true;
00948 }
00949 
00950 void HeProgFinder::restoreSelectedData(QString& data)
00951 {
00952     (void)data;
00953 }
00954 
00956 
00957 // Cyrrilic specific program finder
00958 // Cyrrilic alphabet list and more
00959 const char* RuProgFinder::searchChars[] = {
00960     "А", "Б", "В", "Г", "Д", "Е", "Ё", "Ж", "З", "И",
00961     "Й", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т",
00962     "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ъ", "Ы", "ь",
00963     "Э", "Ю", "Я", "0", "1", "2", "3", "4", "5", "6",
00964     "7", "8", "9", "@", "A", "B", "C", "D", "E", "F",
00965     "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
00966     "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 0 };
00967 
00968 RuProgFinder::RuProgFinder(MythScreenStack *parentStack, bool gg,
00969                            TV *player, bool embedVideo)
00970             : ProgFinder(parentStack, gg, player, embedVideo)
00971 {
00972     for (numberOfSearchChars = 0; searchChars[numberOfSearchChars];
00973          ++numberOfSearchChars)
00974         ;
00975 }
00976 
00977 void RuProgFinder::initAlphabetList()
00978 {
00979     for (int charNum = 0; charNum < numberOfSearchChars; ++charNum)
00980     {
00981         new MythUIButtonListItem(m_alphabetList, QString::fromUtf8(searchChars[charNum]));
00982     }
00983 }
00984 
00985 // search by cyrillic and latin alphabet
00986 // @ all programm
00987 void RuProgFinder::whereClauseGetSearchData(QString &where, MSqlBindings
00988 &bindings)
00989 {
00990    QDateTime progStart = QDateTime::currentDateTime();
00991    QString searchChar = m_alphabetList->GetValue();
00992 
00993    if (searchChar.isEmpty())
00994        searchChar = searchChars[0];
00995 
00996 
00997   if (searchChar.contains('@'))
00998    {
00999        where = "SELECT DISTINCT title FROM program "
01000                "LEFT JOIN channel ON program.chanid = channel.chanid "
01001                "WHERE channel.visible = 1 AND "
01002                "( "
01003                   "title NOT REGEXP '^[A-Z0-9]' AND "
01004                   "title NOT REGEXP '^The [A-Z0-9]' AND "
01005                   "title NOT REGEXP '^A [A-Z0-9]' AND "
01006                   "title NOT REGEXP '^[0-9]' AND "
01007                   "starttime > :STARTTIME ) ";
01008        if (!m_searchStr.isEmpty())
01009        {
01010            where += "AND title LIKE :SEARCH ";
01011            bindings[":SEARCH"] = '%' + m_searchStr + '%';
01012        }
01013 
01014        where += "ORDER BY title;";
01015 
01016        bindings[":STARTTIME"] =
01017            progStart.addSecs(50 - progStart.time().second());
01018    }
01019    else
01020    {
01021        QString one = searchChar + '%';
01022        QString two = QString("The ") + one;
01023        QString three = QString("A ") + one;
01024        QString four = QString("An ") + one;
01025        QString five = QString("\"") + one;
01026 
01027        where = "SELECT DISTINCT title FROM program "
01028                "LEFT JOIN channel ON program.chanid = channel.chanid "
01029                "WHERE channel.visible = 1 "
01030                "AND ( title LIKE :ONE OR title LIKE :TWO "
01031                "      OR title LIKE :THREE "
01032                "      OR title LIKE :FOUR  "
01033                "      OR title LIKE :FIVE )"
01034                "AND starttime > :STARTTIME ";
01035        if (!m_searchStr.isEmpty())
01036            where += "AND title LIKE :SEARCH ";
01037 
01038        where += "ORDER BY title;";
01039 
01040        bindings[":ONE"] = one;
01041        bindings[":TWO"] = two;
01042        bindings[":THREE"] = three;
01043        bindings[":FOUR"] = four;
01044        bindings[":FIVE"] = five;
01045        bindings[":STARTTIME"] =
01046            progStart.addSecs(50 - progStart.time().second());
01047 
01048        if (!m_searchStr.isEmpty())
01049            bindings[":SEARCH"] = '%' + m_searchStr + '%';
01050    }
01051 }
01052 
01053 bool RuProgFinder::formatSelectedData(QString& data)
01054 {
01055     (void)data;
01056     return true;
01057 }
01058 
01059 bool RuProgFinder::formatSelectedData(QString& data, int charNum)
01060 {
01061     (void)data;
01062     (void)charNum;
01063     return true;
01064 }
01065 
01066 void RuProgFinder::restoreSelectedData(QString& data)
01067 {
01068     (void)data;
01069 }
01071 
01072 SearchInputDialog::SearchInputDialog(MythScreenStack *parent,
01073                                      const QString &defaultValue)
01074                  : MythTextInputDialog(parent, "", FilterNone,
01075                                        false, defaultValue)
01076 {
01077 }
01078 
01079 bool SearchInputDialog::Create(void)
01080 {
01081     if (!LoadWindowFromXML("schedule-ui.xml", "searchpopup", this))
01082         return false;
01083 
01084     MythUIText *messageText = NULL;
01085     MythUIButton *okButton = NULL;
01086     MythUIButton *cancelButton = NULL;
01087 
01088     bool err = false;
01089     UIUtilE::Assign(this, m_textEdit, "input", &err);
01090     UIUtilE::Assign(this, messageText, "message", &err);
01091     UIUtilE::Assign(this, okButton, "ok", &err);
01092     UIUtilW::Assign(this, cancelButton, "cancel");
01093 
01094     if (err)
01095     {
01096         LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'searchpopup'");
01097         return false;
01098     }
01099 
01100     if (cancelButton)
01101         connect(cancelButton, SIGNAL(Clicked()), SLOT(Close()));
01102     connect(okButton, SIGNAL(Clicked()), SLOT(sendResult()));
01103 
01104     m_textEdit->SetFilter(m_filter);
01105     m_textEdit->SetText(m_defaultValue);
01106     m_textEdit->SetPassword(m_isPassword);
01107     connect(m_textEdit, SIGNAL(valueChanged()), SLOT(editChanged()));
01108 
01109     BuildFocusList();
01110 
01111     return true;
01112 }
01113 
01114 void SearchInputDialog::editChanged(void)
01115 {
01116     QString inputString = m_textEdit->GetText();
01117     emit valueChanged(inputString);
01118 
01119     if (m_retObject)
01120     {
01121         //FIXME: add a new event type for this?
01122         DialogCompletionEvent *dce =
01123                 new DialogCompletionEvent(m_id, 0, inputString, "");
01124         QCoreApplication::postEvent(m_retObject, dce);
01125     }
01126 }
01127 
01128 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends