MythTV  0.26-pre
custompriority.cpp
Go to the documentation of this file.
00001 
00002 #include "custompriority.h"
00003 
00004 // qt
00005 #include <QSqlError>
00006 
00007 // libmythbase
00008 #include "mythdb.h"
00009 #include "mythlogging.h"
00010 
00011 // libmyth
00012 #include "mythcorecontext.h"
00013 
00014 // libmythtv
00015 #include "scheduledrecording.h"
00016 #include "channelutil.h"
00017 
00018 // libmythui
00019 #include "mythuibuttonlist.h"
00020 #include "mythuispinbox.h"
00021 #include "mythuitextedit.h"
00022 #include "mythuibutton.h"
00023 #include "mythdialogbox.h"
00024 #include "mythmainwindow.h"
00025 
00026 //mythfrontend
00027 #include "viewschedulediff.h"
00028 
00029 CustomPriority::CustomPriority(MythScreenStack *parent, ProgramInfo *proginfo)
00030               : MythScreenType(parent, "CustomPriority")
00031 {
00032     if (proginfo)
00033         m_pginfo = new ProgramInfo(*proginfo);
00034     else
00035         m_pginfo = new ProgramInfo();
00036 
00037     gCoreContext->addListener(this);
00038 }
00039 
00040 CustomPriority::~CustomPriority(void)
00041 {
00042     delete m_pginfo;
00043 
00044     gCoreContext->removeListener(this);
00045 }
00046 
00047 bool CustomPriority::Create()
00048 {
00049     if (!LoadWindowFromXML("schedule-ui.xml", "custompriority", this))
00050         return false;
00051 
00052     m_ruleList = dynamic_cast<MythUIButtonList *>(GetChild("rules"));
00053     m_clauseList = dynamic_cast<MythUIButtonList *>(GetChild("clauses"));
00054 
00055     m_prioritySpin = dynamic_cast<MythUISpinBox *>(GetChild("priority"));
00056 
00057     m_titleEdit = dynamic_cast<MythUITextEdit *>(GetChild("title"));
00058     m_descriptionEdit = dynamic_cast<MythUITextEdit *>(GetChild("description"));
00059 
00060     m_addButton = dynamic_cast<MythUIButton *>(GetChild("add"));
00061     m_installButton = dynamic_cast<MythUIButton *>(GetChild("install"));
00062     m_testButton = dynamic_cast<MythUIButton *>(GetChild("test"));
00063     m_deleteButton = dynamic_cast<MythUIButton *>(GetChild("delete"));
00064     m_cancelButton = dynamic_cast<MythUIButton *>(GetChild("cancel"));
00065 
00066     if (!m_ruleList || !m_clauseList || !m_prioritySpin || !m_titleEdit ||
00067         !m_descriptionEdit || !m_addButton || !m_installButton ||
00068         !m_testButton || !m_deleteButton || !m_cancelButton)
00069     {
00070         LOG(VB_GENERAL, LOG_ERR,
00071             "CustomPriority, theme is missing required elements");
00072         return false;
00073     }
00074 
00075     connect(m_ruleList, SIGNAL(itemSelected(MythUIButtonListItem *)),
00076                 SLOT(ruleChanged(MythUIButtonListItem *)));
00077 
00078     connect(m_titleEdit, SIGNAL(valueChanged()), SLOT(textChanged()));
00079     m_titleEdit->SetMaxLength(128);
00080     connect(m_descriptionEdit, SIGNAL(valueChanged()), SLOT(textChanged()));
00081     m_descriptionEdit->SetMaxLength(0);
00082 
00083     connect(m_addButton, SIGNAL(Clicked()), SLOT(addClicked()));
00084     connect(m_testButton, SIGNAL(Clicked()), SLOT(testClicked()));
00085     connect(m_installButton, SIGNAL(Clicked()), SLOT(installClicked()));
00086     connect(m_deleteButton, SIGNAL(Clicked()), SLOT(deleteClicked()));
00087     connect(m_cancelButton, SIGNAL(Clicked()), SLOT(Close()));
00088 
00089     loadData();
00090 
00091     BuildFocusList();
00092 
00093     return true;
00094 }
00095 
00096 void CustomPriority::loadData()
00097 {
00098     QString baseTitle = m_pginfo->GetTitle();
00099     baseTitle.remove(QRegExp(" \\(.*\\)$"));
00100 
00101     QString quoteTitle = baseTitle;
00102     quoteTitle.replace("\'","\'\'");
00103 
00104     m_prioritySpin->SetRange(-99,99,1);
00105     m_prioritySpin->SetValue(1);
00106 
00107     RuleInfo rule;
00108     rule.priority = QString().setNum(1);
00109 
00110     new MythUIButtonListItem(m_ruleList, tr("<New priority rule>"),
00111                              qVariantFromValue(rule));
00112 
00113     MSqlQuery result(MSqlQuery::InitCon());
00114     result.prepare("SELECT priorityname, recpriority, selectclause "
00115                    "FROM powerpriority ORDER BY priorityname;");
00116 
00117     if (result.exec())
00118     {
00119         MythUIButtonListItem *item = NULL;
00120         while (result.next())
00121         {
00122             QString trimTitle = result.value(0).toString();
00123             trimTitle.remove(QRegExp(" \\(.*\\)$"));
00124 
00125             rule.title = trimTitle;
00126             rule.priority = result.value(1).toString();
00127             rule.description = result.value(2).toString();
00128 
00129             item = new MythUIButtonListItem(m_ruleList, rule.title,
00130                                             qVariantFromValue(rule));
00131 
00132             if (trimTitle == baseTitle)
00133                 m_ruleList->SetItemCurrent(item);
00134         }
00135     }
00136     else
00137         MythDB::DBError("Get power search rules query", result);
00138 
00139     loadExampleRules();
00140 
00141     if (!m_pginfo->GetTitle().isEmpty())
00142     {
00143         m_titleEdit->SetText(baseTitle);
00144         m_descriptionEdit->SetText("program.title = '" + quoteTitle + "' ");
00145         textChanged();
00146     }
00147 
00148     if (m_titleEdit->GetText().isEmpty())
00149         SetFocusWidget(m_ruleList);
00150     else
00151         SetFocusWidget(m_clauseList);
00152 }
00153 
00154 void CustomPriority::loadExampleRules()
00155 {
00156     QMap<QString, QString> examples;
00157     examples.insert(tr("Modify priority for an input (Input priority)"),
00158                     "cardinput.cardinputid = 1");
00159     examples.insert(tr("Modify priority for all inputs on a card"),
00160                     "cardinput.cardid = 2");
00161     examples.insert(tr("Modify priority for every card on a host"),
00162                     "capturecard.hostname = 'mythbox'");
00163     examples.insert(tr("Only one specific channel ID (Channel priority)"),
00164                     "channel.chanid = '1003' ");
00165     examples.insert(tr("Only a certain channel number"),
00166                     "channel.channum = '3' ");
00167     examples.insert(tr("Only channels that carry a specific station"),
00168                     "channel.callsign = 'ESPN' ");
00169     examples.insert(tr("Match related callsigns"),
00170                     "channel.callsign LIKE 'HBO%' ");
00171     examples.insert(tr("Only channels marked as commercial free"),
00172                     QString("channel.commmethod = %1 ")
00173                         .arg(COMM_DETECT_COMMFREE));
00174     examples.insert(tr("Modify priority for a station on an input"),
00175                     "channel.callsign = 'ESPN' AND cardinput.cardinputid = 2");
00176     examples.insert(tr("Priority for all matching titles"),
00177                     "program.title LIKE 'CSI: %' ");
00178     examples.insert(tr("Only shows marked as HDTV"),
00179                     "program.hdtv > 0 ");
00180     examples.insert(tr("Close Captioned priority"),
00181                     "program.closecaptioned > 0 ");
00182     examples.insert(tr("New episodes only"),
00183                     "program.previouslyshown = 0 ");
00184     examples.insert(tr("Modify unidentified episodes"),
00185                     "program.generic = 0 ");
00186     examples.insert(tr("First showing of each episode"),
00187                     "program.first > 0 ");
00188     examples.insert(tr("Last showing of each episode"),
00189                     "program.last > 0 ");
00190     examples.insert(tr("Priority for any show with End Late time"),
00191                     "RECTABLE.endoffset > 0 ");
00192     examples.insert(tr("Priority for a category"),
00193                     "program.category = 'Reality' ");
00194     examples.insert(QString("%1 ('movie', 'series', 'sports', 'tvshow')")
00195                     .arg(tr("Priority for a category type")),
00196                     "program.category_type = 'sports' ");
00197     examples.insert(tr("Modify priority by star rating (0.0 to 1.0 for "
00198                        "movies only)"),
00199                     "program.stars >= 0.75 ");
00200     examples.insert(tr("Priority when shown once (complete example)"),
00201                     "program.first > 0 AND program.last > 0");
00202     examples.insert(tr("Prefer a host for a storage group (complete example)"),
00203                     QString("RECTABLE.storagegroup = 'Archive' "
00204                             "AND capturecard.hostname = 'mythbox' "));
00205     examples.insert(tr("Priority for HD shows under two hours (complete "
00206                        "example)"),
00207                     "program.hdtv > 0 AND program.starttime > "
00208                     "DATE_SUB(program.endtime, INTERVAL 2 HOUR) ");
00209     examples.insert(tr("Priority for movies by the year of release (complete "
00210                        "example)"),
00211                     "program.category_type = 'movie' "
00212                     "AND program.airdate >= 2006 ");
00213     examples.insert(tr("Prefer movies when shown at night (complete example)"),
00214                     "program.category_type = 'movie' "
00215                     "AND HOUR(program.starttime) < 6 ");
00216     examples.insert(tr("Prefer a host for live sports with overtime (complete "
00217                     "example)"),
00218                     "RECTABLE.endoffset > 0 "
00219                     "AND program.category = 'Sports event' "
00220                     "AND capturecard.hostname = 'mythbox' ");
00221     examples.insert(tr("Avoid poor signal quality (complete example)"),
00222                     "cardinput.cardinputid = 1 AND "
00223                     "channel.channum IN (3, 5, 39, 66) ");
00224 
00225     QMapIterator<QString, QString> it(examples);
00226     while (it.hasNext())
00227     {
00228         it.next();
00229         new MythUIButtonListItem(m_clauseList, it.key(),
00230                                  qVariantFromValue(it.value()));
00231     }
00232 }
00233 
00234 void CustomPriority::ruleChanged(MythUIButtonListItem *item)
00235 {
00236     if (!item)
00237         return;
00238 
00239     RuleInfo rule = qVariantValue<RuleInfo>(item->GetData());
00240 
00241     m_titleEdit->SetText(rule.title);
00242 
00243     m_descriptionEdit->SetText(rule.description);
00244     m_prioritySpin->SetValue(rule.priority);
00245     m_deleteButton->SetEnabled((bool)m_ruleList->GetCurrentPos());
00246     textChanged();
00247 }
00248 
00249 void CustomPriority::textChanged(void)
00250 {
00251     bool hastitle = !m_titleEdit->GetText().isEmpty();
00252     bool hasdesc = !m_descriptionEdit->GetText().isEmpty();
00253 
00254     m_testButton->SetEnabled(hasdesc);
00255     m_installButton->SetEnabled(hastitle && hasdesc);
00256 }
00257 
00258 void CustomPriority::addClicked(void)
00259 {
00260     MythUIButtonListItem *item = m_clauseList->GetItemCurrent();
00261 
00262     if (!item)
00263         return;
00264 
00265     QString clause;
00266 
00267     QString desc = m_descriptionEdit->GetText();
00268 
00269     if (desc.contains(QRegExp("\\S")))
00270         clause = "AND ";
00271     clause = item->GetData().toString();
00272     m_descriptionEdit->SetText(desc.append(clause));
00273 }
00274 
00275 void CustomPriority::testClicked(void)
00276 {
00277     if (!checkSyntax())
00278         return;
00279 
00280     testSchedule();
00281 }
00282 
00283 void CustomPriority::installClicked(void)
00284 {
00285     if (!checkSyntax())
00286         return;
00287 
00288     MythUIButtonListItem *item = m_prioritySpin->GetItemCurrent();
00289     if (!item)
00290         return;
00291 
00292     MSqlQuery query(MSqlQuery::InitCon());
00293     query.prepare("DELETE FROM powerpriority WHERE priorityname = :NAME;");
00294     query.bindValue(":NAME", m_titleEdit->GetText());
00295 
00296     if (!query.exec())
00297         MythDB::DBError("Install power search delete", query);
00298 
00299     query.prepare("INSERT INTO powerpriority "
00300                   "(priorityname, recpriority, selectclause) "
00301                   "VALUES(:NAME,:VALUE,:CLAUSE);");
00302     query.bindValue(":NAME", m_titleEdit->GetText());
00303     query.bindValue(":VALUE", item->GetText());
00304     query.bindValue(":CLAUSE", m_descriptionEdit->GetText());
00305 
00306     if (!query.exec())
00307         MythDB::DBError("Install power search insert", query);
00308     else
00309         ScheduledRecording::ReschedulePlace("InstallCustomPriority");
00310 
00311     Close();
00312 }
00313 
00314 void CustomPriority::deleteClicked(void)
00315 {
00316     if (!checkSyntax())
00317         return;
00318 
00319     MSqlQuery query(MSqlQuery::InitCon());
00320     query.prepare("DELETE FROM powerpriority "
00321                    "WHERE priorityname=:NAME;");
00322     query.bindValue(":NAME", m_titleEdit->GetText());
00323 
00324     if (!query.exec())
00325         MythDB::DBError("Delete power search query", query);
00326     else
00327         ScheduledRecording::ReschedulePlace("DeleteCustomPriority");
00328 
00329     Close();
00330 }
00331 
00332 bool CustomPriority::checkSyntax(void)
00333 {
00334     bool ret = false;
00335     QString msg;
00336 
00337     QString desc = m_descriptionEdit->GetText();
00338 
00339     if (desc.contains(QRegExp("^\\s*AND\\s", Qt::CaseInsensitive)))
00340     {
00341         msg = "Power Priority rules do not reqiure a leading \"AND\"";
00342     }
00343     else if (desc.contains(';'))
00344     {
00345         msg  = "Power Priority rules cannot include semicolon ( ; ) ";
00346         msg += "statement terminators.";
00347     }
00348     else
00349     {
00350         QString qstr = QString("SELECT (%1) FROM (recordmatch, record, "
00351                                "program, channel, cardinput, capturecard, "
00352                                "oldrecorded) WHERE NULL").arg(desc);
00353         while (1)
00354         {
00355             int i = qstr.indexOf("RECTABLE");
00356             if (i == -1) break;
00357             qstr = qstr.replace(i, strlen("RECTABLE"), "record");
00358         }
00359 
00360         MSqlQuery query(MSqlQuery::InitCon());
00361         query.prepare(qstr);
00362 
00363         if (query.exec())
00364         {
00365             ret = true;
00366         }
00367         else
00368         {
00369             msg = tr("An error was found when checking") + ":\n\n";
00370             msg += query.executedQuery();
00371             msg += "\n\n" + tr("The database error was") + ":\n";
00372             msg += query.lastError().databaseText();
00373             ret = false;
00374         }
00375     }
00376 
00377     if (!msg.isEmpty())
00378         ShowOkPopup(msg);
00379 
00380     return ret;
00381 }
00382 
00383 void CustomPriority::testSchedule(void)
00384 {
00385     MythUIButtonListItem *item = m_prioritySpin->GetItemCurrent();
00386     if (!item)
00387         return;
00388 
00389     QString ttable = "powerpriority_tmp";
00390 
00391     MSqlQueryInfo dbcon = MSqlQuery::SchedCon();
00392     MSqlQuery query(dbcon);
00393     QString thequery;
00394 
00395     thequery = "SELECT GET_LOCK(:LOCK, 2);";
00396     query.prepare(thequery);
00397     query.bindValue(":LOCK", "DiffSchedule");
00398     if (!query.exec())
00399     {
00400         QString msg =
00401             QString("DB Error (Obtaining lock in testRecording): \n"
00402                     "Query was: %1 \nError was: %2 \n")
00403             .arg(thequery)
00404             .arg(MythDB::DBErrorMessage(query.lastError()));
00405         LOG(VB_GENERAL, LOG_ERR, msg);
00406         return;
00407     }
00408 
00409     thequery = QString("DROP TABLE IF EXISTS %1;").arg(ttable);
00410     query.prepare(thequery);
00411     if (!query.exec())
00412     {
00413         QString msg =
00414             QString("DB Error (deleting old table in testRecording): \n"
00415                     "Query was: %1 \nError was: %2 \n")
00416             .arg(thequery)
00417             .arg(MythDB::DBErrorMessage(query.lastError()));
00418         LOG(VB_GENERAL, LOG_ERR, msg);
00419         return;
00420     }
00421 
00422     thequery = QString("CREATE TABLE %1 SELECT * FROM powerpriority;")
00423                        .arg(ttable);
00424     query.prepare(thequery);
00425     if (!query.exec())
00426     {
00427         QString msg =
00428             QString("DB Error (create new table): \n"
00429                     "Query was: %1 \nError was: %2 \n")
00430             .arg(thequery)
00431             .arg(MythDB::DBErrorMessage(query.lastError()));
00432         LOG(VB_GENERAL, LOG_ERR, msg);
00433         return;
00434     }
00435 
00436     query.prepare(QString("DELETE FROM %1 WHERE priorityname = :NAME;")
00437                           .arg(ttable));
00438     query.bindValue(":NAME", m_titleEdit->GetText());
00439 
00440     if (!query.exec())
00441         MythDB::DBError("Test power search delete", query);
00442 
00443     thequery = QString("INSERT INTO %1 "
00444                        "(priorityname, recpriority, selectclause) "
00445                        "VALUES(:NAME,:VALUE,:CLAUSE);").arg(ttable);
00446     query.prepare(thequery);
00447     query.bindValue(":NAME", m_titleEdit->GetText());
00448     query.bindValue(":VALUE", item->GetText());
00449     query.bindValue(":CLAUSE", m_descriptionEdit->GetText());
00450 
00451     if (!query.exec())
00452         MythDB::DBError("Test power search insert", query);
00453 
00454     QString ltitle = tr("Power Priority");
00455     if (!m_titleEdit->GetText().isEmpty())
00456         ltitle = m_titleEdit->GetText();
00457 
00458     MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
00459     ViewScheduleDiff *vsd = new ViewScheduleDiff(mainStack, ttable, 0, ltitle);
00460 
00461     if (vsd->Create())
00462         mainStack->AddScreen(vsd);
00463     else
00464         delete vsd;
00465 
00466     thequery = "SELECT RELEASE_LOCK(:LOCK);";
00467     query.prepare(thequery);
00468     query.bindValue(":LOCK", "DiffSchedule");
00469     if (!query.exec())
00470     {
00471         QString msg =
00472             QString("DB Error (free lock): \n"
00473                     "Query was: %1 \nError was: %2 \n")
00474             .arg(thequery)
00475             .arg(MythDB::DBErrorMessage(query.lastError()));
00476         LOG(VB_GENERAL, LOG_ERR, msg);
00477     }
00478 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends