MythTV  master
custompriority.cpp
Go to the documentation of this file.
1 // Qt
2 #include <QSqlError>
3 
4 // MythTV
6 #include "libmythbase/mythdb.h"
12 #include "libmythui/mythuibutton.h"
16 
17 // MythFrontend
18 #include "custompriority.h"
19 #include "viewschedulediff.h"
20 
22  : MythScreenType(parent, "CustomPriority")
23 {
24  if (proginfo)
25  m_pginfo = new ProgramInfo(*proginfo);
26  else
27  m_pginfo = new ProgramInfo();
28 
30 }
31 
33 {
34  delete m_pginfo;
35 
37 }
38 
40 {
41  if (!LoadWindowFromXML("schedule-ui.xml", "custompriority", this))
42  return false;
43 
44  m_ruleList = dynamic_cast<MythUIButtonList *>(GetChild("rules"));
45  m_clauseList = dynamic_cast<MythUIButtonList *>(GetChild("clauses"));
46 
47  m_prioritySpin = dynamic_cast<MythUISpinBox *>(GetChild("priority"));
48 
49  m_titleEdit = dynamic_cast<MythUITextEdit *>(GetChild("title"));
50  m_descriptionEdit = dynamic_cast<MythUITextEdit *>(GetChild("description"));
51 
52  m_addButton = dynamic_cast<MythUIButton *>(GetChild("add"));
53  m_installButton = dynamic_cast<MythUIButton *>(GetChild("install"));
54  m_testButton = dynamic_cast<MythUIButton *>(GetChild("test"));
55  m_deleteButton = dynamic_cast<MythUIButton *>(GetChild("delete"));
56  m_cancelButton = dynamic_cast<MythUIButton *>(GetChild("cancel"));
57 
61  {
62  LOG(VB_GENERAL, LOG_ERR,
63  "CustomPriority, theme is missing required elements");
64  return false;
65  }
66 
69 
74 
80 
81  loadData();
82 
84 
85  return true;
86 }
87 
89 {
90  QString baseTitle = m_pginfo->GetTitle();
91  baseTitle.remove(RecordingInfo::kReSearchTypeName);
92 
93  QString quoteTitle = baseTitle;
94  quoteTitle.replace("\'","\'\'");
95 
96  m_prioritySpin->SetRange(-99,99,1);
98 
99  RuleInfo rule;
100  rule.priority = QString().setNum(1);
101 
102  new MythUIButtonListItem(m_ruleList, tr("<New priority rule>"),
103  QVariant::fromValue(rule));
104 
105  MSqlQuery result(MSqlQuery::InitCon());
106  result.prepare("SELECT priorityname, recpriority, selectclause "
107  "FROM powerpriority ORDER BY priorityname;");
108 
109  if (result.exec())
110  {
111  MythUIButtonListItem *item = nullptr;
112  while (result.next())
113  {
114  QString trimTitle = result.value(0).toString();
115  trimTitle.remove(RecordingInfo::kReSearchTypeName);
116 
117  rule.title = trimTitle;
118  rule.priority = result.value(1).toString();
119  rule.description = result.value(2).toString();
120 
121  item = new MythUIButtonListItem(m_ruleList, rule.title,
122  QVariant::fromValue(rule));
123 
124  if (trimTitle == baseTitle)
125  m_ruleList->SetItemCurrent(item);
126  }
127  }
128  else
129  MythDB::DBError("Get power search rules query", result);
130 
132 
133  if (!m_pginfo->GetTitle().isEmpty())
134  {
135  m_titleEdit->SetText(baseTitle);
136  m_descriptionEdit->SetText("program.title = '" + quoteTitle + "' ");
137  textChanged();
138  }
139 
140  if (m_titleEdit->GetText().isEmpty())
142  else
144 }
145 
147 {
148  QMap<QString, QString> examples;
149  examples.insert(tr("Modify priority for an input (Input priority)"),
150  "capturecard.cardid = 1");
151  examples.insert(tr("Modify priority for every card on a host"),
152  "capturecard.hostname = 'mythbox'");
153  examples.insert(tr("Only one specific channel ID (Channel priority)"),
154  "channel.chanid = '1003' ");
155  examples.insert(tr("Only a certain channel number"),
156  "channel.channum = '3' ");
157  examples.insert(tr("Only channels that carry a specific station"),
158  "channel.callsign = 'ESPN' ");
159  examples.insert(tr("Match related callsigns"),
160  "channel.callsign LIKE 'HBO%' ");
161  examples.insert(tr("Only channels marked as commercial free"),
162  QString("channel.commmethod = %1 ")
163  .arg(COMM_DETECT_COMMFREE));
164  examples.insert(tr("Modify priority for a station on an input"),
165  "channel.callsign = 'ESPN' AND capturecard.cardid = 2");
166  examples.insert(tr("Priority for all matching titles"),
167  "program.title LIKE 'CSI: %' ");
168  examples.insert(tr("Only shows marked as HDTV"),
169  "program.hdtv > 0 ");
170  examples.insert(tr("Close Captioned priority"),
171  "program.closecaptioned > 0 ");
172  examples.insert(tr("New episodes only"),
173  "program.previouslyshown = 0 ");
174  examples.insert(tr("Modify unidentified episodes"),
175  "program.generic = 0 ");
176  examples.insert(tr("First showing of each episode"),
177  "program.first > 0 ");
178  examples.insert(tr("Last showing of each episode"),
179  "program.last > 0 ");
180  examples.insert(tr("Priority for any show with End Late time"),
181  "RECTABLE.endoffset > 0 ");
182  examples.insert(tr("Priority for a category"),
183  "program.category = 'Reality' ");
184  examples.insert(QString("%1 ('movie', 'series', 'sports', 'tvshow')")
185  .arg(tr("Priority for a category type")),
186  "program.category_type = 'sports' ");
187  examples.insert(tr("Modify priority by star rating (0.0 to 1.0 for "
188  "movies only)"),
189  "program.stars >= 0.75 ");
190  examples.insert(tr("Priority when shown once (complete example)"),
191  "program.first > 0 AND program.last > 0");
192  examples.insert(tr("Prefer a host for a storage group (complete example)"),
193  QString("RECTABLE.storagegroup = 'Archive' "
194  "AND capturecard.hostname = 'mythbox' "));
195  examples.insert(tr("Priority for HD shows under two hours (complete "
196  "example)"),
197  "program.hdtv > 0 AND program.starttime > "
198  "DATE_SUB(program.endtime, INTERVAL 2 HOUR) ");
199  examples.insert(tr("Priority for movies by the year of release (complete "
200  "example)"),
201  "program.category_type = 'movie' "
202  "AND program.airdate >= 2006 ");
203  examples.insert(tr("Prefer movies when shown at night (complete example)"),
204  "program.category_type = 'movie' "
205  "AND HOUR(program.starttime) < 6 ");
206  examples.insert(tr("Prefer a host for live sports with overtime (complete "
207  "example)"),
208  "RECTABLE.endoffset > 0 "
209  "AND program.category = 'Sports event' "
210  "AND capturecard.hostname = 'mythbox' ");
211  examples.insert(tr("Avoid poor signal quality (complete example)"),
212  "capturecard.cardid = 1 AND "
213  "channel.channum IN (3, 5, 39, 66) ");
214 
215  QMapIterator<QString, QString> it(examples);
216  while (it.hasNext())
217  {
218  it.next();
219  new MythUIButtonListItem(m_clauseList, it.key(),
220  QVariant::fromValue(it.value()));
221  }
222 }
223 
225 {
226  if (!item)
227  return;
228 
229  auto rule = item->GetData().value<RuleInfo>();
230 
231  m_titleEdit->SetText(rule.title);
232 
233  m_descriptionEdit->SetText(rule.description);
234  m_prioritySpin->SetValue(rule.priority);
236  textChanged();
237 }
238 
240 {
241  bool hastitle = !m_titleEdit->GetText().isEmpty();
242  bool hasdesc = !m_descriptionEdit->GetText().isEmpty();
243 
244  m_testButton->SetEnabled(hasdesc);
245  m_installButton->SetEnabled(hastitle && hasdesc);
246 }
247 
249 {
251 
252  if (!item)
253  return;
254 
255  QString clause;
256 
257  QString desc = m_descriptionEdit->GetText();
258 
259  static const QRegularExpression kNonWhiteSpaceRE { "\\S" };
260  if (desc.contains(kNonWhiteSpaceRE))
261  clause = "AND ";
262  clause += item->GetData().toString();
263  m_descriptionEdit->SetText(desc.append(clause));
264 }
265 
267 {
268  if (!checkSyntax())
269  return;
270 
271  testSchedule();
272 }
273 
275 {
276  if (!checkSyntax())
277  return;
278 
280  if (!item)
281  return;
282 
283  MSqlQuery query(MSqlQuery::InitCon());
284  query.prepare("DELETE FROM powerpriority WHERE priorityname = :NAME;");
285  query.bindValue(":NAME", m_titleEdit->GetText());
286 
287  if (!query.exec())
288  MythDB::DBError("Install power search delete", query);
289 
290  query.prepare("INSERT INTO powerpriority "
291  "(priorityname, recpriority, selectclause) "
292  "VALUES(:NAME,:VALUE,:CLAUSE);");
293  query.bindValue(":NAME", m_titleEdit->GetText());
294  query.bindValue(":VALUE", item->GetText());
295  query.bindValue(":CLAUSE", m_descriptionEdit->GetText());
296 
297  if (!query.exec())
298  MythDB::DBError("Install power search insert", query);
299  else
300  ScheduledRecording::ReschedulePlace("InstallCustomPriority");
301 
302  Close();
303 }
304 
306 {
307  if (!checkSyntax())
308  return;
309 
310  MSqlQuery query(MSqlQuery::InitCon());
311  query.prepare("DELETE FROM powerpriority "
312  "WHERE priorityname=:NAME;");
313  query.bindValue(":NAME", m_titleEdit->GetText());
314 
315  if (!query.exec())
316  MythDB::DBError("Delete power search query", query);
317  else
318  ScheduledRecording::ReschedulePlace("DeleteCustomPriority");
319 
320  Close();
321 }
322 
324 {
325  bool ret = false;
326  QString msg;
327 
328  QString desc = m_descriptionEdit->GetText();
329 
330  if (desc.contains(RecordingInfo::kReLeadingAnd))
331  {
332  msg = "Power Priority rules do not reqiure a leading \"AND\"";
333  }
334  else if (desc.contains(';'))
335  {
336  msg = "Power Priority rules cannot include semicolon ( ; ) ";
337  msg += "statement terminators.";
338  }
339  else
340  {
341  QString qstr = QString("SELECT (%1) FROM (recordmatch, record, "
342  "program, channel, capturecard, "
343  "oldrecorded) WHERE NULL").arg(desc);
344  while (true)
345  {
346  int i = qstr.indexOf("RECTABLE");
347  if (i == -1) break;
348  qstr = qstr.replace(i, strlen("RECTABLE"), "record");
349  }
350 
351  MSqlQuery query(MSqlQuery::InitCon());
352  query.prepare(qstr);
353 
354  if (query.exec())
355  {
356  ret = true;
357  }
358  else
359  {
360  msg = tr("An error was found when checking") + ":\n\n";
361  msg += query.executedQuery();
362  msg += "\n\n" + tr("The database error was") + ":\n";
363  msg += query.lastError().databaseText();
364  ret = false;
365  }
366  }
367 
368  if (!msg.isEmpty())
369  ShowOkPopup(msg);
370 
371  return ret;
372 }
373 
375 {
377  if (!item)
378  return;
379 
380  QString ttable = "powerpriority_tmp";
381 
383  MSqlQuery query(dbcon);
384  QString thequery;
385 
386  thequery = "SELECT GET_LOCK(:LOCK, 2);";
387  query.prepare(thequery);
388  query.bindValue(":LOCK", "DiffSchedule");
389  if (!query.exec())
390  {
391  QString msg =
392  QString("DB Error (Obtaining lock in testRecording): \n"
393  "Query was: %1 \nError was: %2 \n")
394  .arg(thequery,
396  LOG(VB_GENERAL, LOG_ERR, msg);
397  return;
398  }
399 
400  thequery = QString("DROP TABLE IF EXISTS %1;").arg(ttable);
401  query.prepare(thequery);
402  if (!query.exec())
403  {
404  QString msg =
405  QString("DB Error (deleting old table in testRecording): \n"
406  "Query was: %1 \nError was: %2 \n")
407  .arg(thequery,
409  LOG(VB_GENERAL, LOG_ERR, msg);
410  return;
411  }
412 
413  thequery = QString("CREATE TABLE %1 SELECT * FROM powerpriority;")
414  .arg(ttable);
415  query.prepare(thequery);
416  if (!query.exec())
417  {
418  QString msg =
419  QString("DB Error (create new table): \n"
420  "Query was: %1 \nError was: %2 \n")
421  .arg(thequery,
423  LOG(VB_GENERAL, LOG_ERR, msg);
424  return;
425  }
426 
427  query.prepare(QString("DELETE FROM %1 WHERE priorityname = :NAME;")
428  .arg(ttable));
429  query.bindValue(":NAME", m_titleEdit->GetText());
430 
431  if (!query.exec())
432  MythDB::DBError("Test power search delete", query);
433 
434  thequery = QString("INSERT INTO %1 "
435  "(priorityname, recpriority, selectclause) "
436  "VALUES(:NAME,:VALUE,:CLAUSE);").arg(ttable);
437  query.prepare(thequery);
438  query.bindValue(":NAME", m_titleEdit->GetText());
439  query.bindValue(":VALUE", item->GetText());
440  query.bindValue(":CLAUSE", m_descriptionEdit->GetText());
441 
442  if (!query.exec())
443  MythDB::DBError("Test power search insert", query);
444 
445  QString ltitle = tr("Power Priority");
446  if (!m_titleEdit->GetText().isEmpty())
447  ltitle = m_titleEdit->GetText();
448 
450  auto *vsd = new ViewScheduleDiff(mainStack, ttable, 0, ltitle);
451 
452  if (vsd->Create())
453  mainStack->AddScreen(vsd);
454  else
455  delete vsd;
456 
457  thequery = "SELECT RELEASE_LOCK(:LOCK);";
458  query.prepare(thequery);
459  query.bindValue(":LOCK", "DiffSchedule");
460  if (!query.exec())
461  {
462  QString msg =
463  QString("DB Error (free lock): \n"
464  "Query was: %1 \nError was: %2 \n")
465  .arg(thequery,
467  LOG(VB_GENERAL, LOG_ERR, msg);
468  }
469 }
MythUIButton::Clicked
void Clicked()
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:807
CustomPriority::m_deleteButton
MythUIButton * m_deleteButton
Definition: custompriority.h:52
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:315
MythUITextEdit::SetMaxLength
void SetMaxLength(int length)
Definition: mythuitextedit.cpp:192
CustomPriority::m_cancelButton
MythUIButton * m_cancelButton
Definition: custompriority.h:53
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1587
RecordingInfo::kReSearchTypeName
static const QRegularExpression kReSearchTypeName
Definition: recordinginfo.h:197
CustomPriority::m_descriptionEdit
MythUITextEdit * m_descriptionEdit
Definition: custompriority.h:45
CustomPriority::checkSyntax
bool checkSyntax(void)
Definition: custompriority.cpp:323
CustomPriority::addClicked
void addClicked(void)
Definition: custompriority.cpp:248
RuleInfo::description
QString description
Definition: custompriority.h:59
mythdb.h
MythDB::DBErrorMessage
static QString DBErrorMessage(const QSqlError &err)
Definition: mythdb.cpp:232
RuleInfo
Definition: custompriority.h:56
MythScreenType::Close
virtual void Close()
Definition: mythscreentype.cpp:386
MythUIType::GetChild
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:133
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:205
MythScreenStack
Definition: mythscreenstack.h:16
RecordingInfo::kReLeadingAnd
static const QRegularExpression kReLeadingAnd
Definition: recordinginfo.h:200
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:608
MythUITextEdit
A text entry and edit widget.
Definition: mythuitextedit.h:34
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
CustomPriority::m_testButton
MythUIButton * m_testButton
Definition: custompriority.h:50
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:45
CustomPriority::m_titleEdit
MythUITextEdit * m_titleEdit
Definition: custompriority.h:44
MythUITextEdit::GetText
QString GetText(void) const
Definition: mythuitextedit.h:50
MythUISpinBox::SetRange
void SetRange(int low, int high, int step, uint pageMultiple=5)
Set the lower and upper bounds of the spinbox, the interval and page amount.
Definition: mythuispinbox.cpp:26
mythuibuttonlist.h
RuleInfo::title
QString title
Definition: custompriority.h:57
MythObservable::addListener
void addListener(QObject *listener)
Add a listener to the observable.
Definition: mythobservable.cpp:38
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
CustomPriority::Create
bool Create() override
Definition: custompriority.cpp:39
MythUISpinBox::SetValue
void SetValue(int val) override
Definition: mythuispinbox.h:26
viewschedulediff.h
MythUITextEdit::SetText
void SetText(const QString &text, bool moveCursor=true)
Definition: mythuitextedit.cpp:197
COMM_DETECT_COMMFREE
@ COMM_DETECT_COMMFREE
Definition: programtypes.h:130
mythlogging.h
MSqlQueryInfo
MSqlDatabase Info, used by MSqlQuery. Do not use directly.
Definition: mythdbcon.h:93
MythUIButtonList::GetCurrentPos
int GetCurrentPos() const
Definition: mythuibuttonlist.h:238
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:118
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:540
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:361
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:227
custompriority.h
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:206
CustomPriority::deleteClicked
void deleteClicked(void)
Definition: custompriority.cpp:305
CustomPriority::testSchedule
void testSchedule(void)
Definition: custompriority.cpp:374
CustomPriority::loadExampleRules
void loadExampleRules(void)
Definition: custompriority.cpp:146
MythUIButton
A single button widget.
Definition: mythuibutton.h:21
MSqlQuery::SchedCon
static MSqlQueryInfo SchedCon()
Returns dedicated connection. (Required for using temporary SQL tables.)
Definition: mythdbcon.cpp:570
scheduledrecording.h
MythUIType::SetEnabled
void SetEnabled(bool enable)
Definition: mythuitype.cpp:1131
CustomPriority::CustomPriority
CustomPriority(MythScreenStack *parent, ProgramInfo *proginfo=nullptr)
Definition: custompriority.cpp:21
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3665
CustomPriority::textChanged
void textChanged()
Definition: custompriority.cpp:239
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:54
CustomPriority::ruleChanged
void ruleChanged(MythUIButtonListItem *item)
Definition: custompriority.cpp:224
ScheduledRecording::ReschedulePlace
static void ReschedulePlace(const QString &why)
Definition: scheduledrecording.h:33
channelutil.h
MSqlQuery::lastError
QSqlError lastError(void) const
Definition: mythdbcon.h:214
MythUIButtonListItem::GetText
QString GetText(const QString &name="") const
Definition: mythuibuttonlist.cpp:3315
mythuispinbox.h
ViewScheduleDiff
Definition: viewschedulediff.h:22
CustomPriority::m_ruleList
MythUIButtonList * m_ruleList
Definition: custompriority.h:41
CustomPriority::testClicked
void testClicked(void)
Definition: custompriority.cpp:266
CustomPriority::loadData
void loadData(void)
Definition: custompriority.cpp:88
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
mythcorecontext.h
MSqlQuery::executedQuery
QString executedQuery(void) const
Definition: mythdbcon.h:206
mythuitextedit.h
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:695
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:883
CustomPriority::m_installButton
MythUIButton * m_installButton
Definition: custompriority.h:51
CustomPriority::installClicked
void installClicked(void)
Definition: custompriority.cpp:274
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:102
MythUIButtonList::SetItemCurrent
void SetItemCurrent(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1554
MythUISpinBox
A widget for offering a range of numerical values where only the the bounding values and interval are...
Definition: mythuispinbox.h:16
mythuibutton.h
MythUITextEdit::valueChanged
void valueChanged()
CustomPriority::~CustomPriority
~CustomPriority() override
Definition: custompriority.cpp:32
RuleInfo::priority
QString priority
Definition: custompriority.h:58
MythUIButtonList
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
Definition: mythuibuttonlist.h:191
CustomPriority::m_addButton
MythUIButton * m_addButton
Definition: custompriority.h:49
CustomPriority::m_clauseList
MythUIButtonList * m_clauseList
Definition: custompriority.h:42
CustomPriority::m_pginfo
ProgramInfo * m_pginfo
Definition: custompriority.h:39
mythmainwindow.h
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:50
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:562
MythObservable::removeListener
void removeListener(QObject *listener)
Remove a listener to the observable.
Definition: mythobservable.cpp:55
CustomPriority::m_prioritySpin
MythUISpinBox * m_prioritySpin
Definition: custompriority.h:47
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:832