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 
131  // No memory leak. In the previous while loop, MythUIButtonListItem
132  // adds the new item into m_ruleList.
133  // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
135 
136  if (!m_pginfo->GetTitle().isEmpty())
137  {
138  m_titleEdit->SetText(baseTitle);
139  m_descriptionEdit->SetText("program.title = '" + quoteTitle + "' ");
140  textChanged();
141  }
142 
143  if (m_titleEdit->GetText().isEmpty())
145  else
147 }
148 
150 {
151  QMap<QString, QString> examples;
152  examples.insert(tr("Modify priority for an input (Input priority)"),
153  "capturecard.cardid = 1");
154  examples.insert(tr("Modify priority for every card on a host"),
155  "capturecard.hostname = 'mythbox'");
156  examples.insert(tr("Only one specific channel ID (Channel priority)"),
157  "channel.chanid = '1003' ");
158  examples.insert(tr("Only a certain channel number"),
159  "channel.channum = '3' ");
160  examples.insert(tr("Only channels that carry a specific station"),
161  "channel.callsign = 'ESPN' ");
162  examples.insert(tr("Match related callsigns"),
163  "channel.callsign LIKE 'HBO%' ");
164  examples.insert(tr("Only channels marked as commercial free"),
165  QString("channel.commmethod = %1 ")
166  .arg(COMM_DETECT_COMMFREE));
167  examples.insert(tr("Modify priority for a station on an input"),
168  "channel.callsign = 'ESPN' AND capturecard.cardid = 2");
169  examples.insert(tr("Priority for all matching titles"),
170  "program.title LIKE 'CSI: %' ");
171  examples.insert(tr("Only shows marked as HDTV"),
172  "program.hdtv > 0 ");
173  examples.insert(tr("Close Captioned priority"),
174  "program.closecaptioned > 0 ");
175  examples.insert(tr("New episodes only"),
176  "program.previouslyshown = 0 ");
177  examples.insert(tr("Modify unidentified episodes"),
178  "program.generic = 0 ");
179  examples.insert(tr("First showing of each episode"),
180  "program.first > 0 ");
181  examples.insert(tr("Last showing of each episode"),
182  "program.last > 0 ");
183  examples.insert(tr("Priority for any show with End Late time"),
184  "RECTABLE.endoffset > 0 ");
185  examples.insert(tr("Priority for a category"),
186  "program.category = 'Reality' ");
187  examples.insert(QString("%1 ('movie', 'series', 'sports', 'tvshow')")
188  .arg(tr("Priority for a category type")),
189  "program.category_type = 'sports' ");
190  examples.insert(tr("Modify priority by star rating (0.0 to 1.0 for "
191  "movies only)"),
192  "program.stars >= 0.75 ");
193  examples.insert(tr("Priority when shown once (complete example)"),
194  "program.first > 0 AND program.last > 0");
195  examples.insert(tr("Prefer a host for a storage group (complete example)"),
196  QString("RECTABLE.storagegroup = 'Archive' "
197  "AND capturecard.hostname = 'mythbox' "));
198  examples.insert(tr("Priority for HD shows under two hours (complete "
199  "example)"),
200  "program.hdtv > 0 AND program.starttime > "
201  "DATE_SUB(program.endtime, INTERVAL 2 HOUR) ");
202  examples.insert(tr("Priority for movies by the year of release (complete "
203  "example)"),
204  "program.category_type = 'movie' "
205  "AND program.airdate >= 2006 ");
206  examples.insert(tr("Prefer movies when shown at night (complete example)"),
207  "program.category_type = 'movie' "
208  "AND HOUR(program.starttime) < 6 ");
209  examples.insert(tr("Prefer a host for live sports with overtime (complete "
210  "example)"),
211  "RECTABLE.endoffset > 0 "
212  "AND program.category = 'Sports event' "
213  "AND capturecard.hostname = 'mythbox' ");
214  examples.insert(tr("Avoid poor signal quality (complete example)"),
215  "capturecard.cardid = 1 AND "
216  "channel.channum IN (3, 5, 39, 66) ");
217 
218  QMapIterator<QString, QString> it(examples);
219  while (it.hasNext())
220  {
221  it.next();
222  new MythUIButtonListItem(m_clauseList, it.key(),
223  QVariant::fromValue(it.value()));
224  }
225 }
226 
228 {
229  if (!item)
230  return;
231 
232  auto rule = item->GetData().value<RuleInfo>();
233 
234  m_titleEdit->SetText(rule.title);
235 
236  m_descriptionEdit->SetText(rule.description);
237  m_prioritySpin->SetValue(rule.priority);
239  textChanged();
240 }
241 
243 {
244  bool hastitle = !m_titleEdit->GetText().isEmpty();
245  bool hasdesc = !m_descriptionEdit->GetText().isEmpty();
246 
247  m_testButton->SetEnabled(hasdesc);
248  m_installButton->SetEnabled(hastitle && hasdesc);
249 }
250 
252 {
254 
255  if (!item)
256  return;
257 
258  QString clause;
259 
260  QString desc = m_descriptionEdit->GetText();
261 
262  static const QRegularExpression kNonWhiteSpaceRE { "\\S" };
263  if (desc.contains(kNonWhiteSpaceRE))
264  clause = "AND ";
265  clause += item->GetData().toString();
266  m_descriptionEdit->SetText(desc.append(clause));
267 }
268 
270 {
271  if (!checkSyntax())
272  return;
273 
274  testSchedule();
275 }
276 
278 {
279  if (!checkSyntax())
280  return;
281 
283  if (!item)
284  return;
285 
286  MSqlQuery query(MSqlQuery::InitCon());
287  query.prepare("DELETE FROM powerpriority WHERE priorityname = :NAME;");
288  query.bindValue(":NAME", m_titleEdit->GetText());
289 
290  if (!query.exec())
291  MythDB::DBError("Install power search delete", query);
292 
293  query.prepare("INSERT INTO powerpriority "
294  "(priorityname, recpriority, selectclause) "
295  "VALUES(:NAME,:VALUE,:CLAUSE);");
296  query.bindValue(":NAME", m_titleEdit->GetText());
297  query.bindValue(":VALUE", item->GetText());
298  query.bindValue(":CLAUSE", m_descriptionEdit->GetText());
299 
300  if (!query.exec())
301  MythDB::DBError("Install power search insert", query);
302  else
303  ScheduledRecording::ReschedulePlace("InstallCustomPriority");
304 
305  Close();
306 }
307 
309 {
310  if (!checkSyntax())
311  return;
312 
313  MSqlQuery query(MSqlQuery::InitCon());
314  query.prepare("DELETE FROM powerpriority "
315  "WHERE priorityname=:NAME;");
316  query.bindValue(":NAME", m_titleEdit->GetText());
317 
318  if (!query.exec())
319  MythDB::DBError("Delete power search query", query);
320  else
321  ScheduledRecording::ReschedulePlace("DeleteCustomPriority");
322 
323  Close();
324 }
325 
327 {
328  bool ret = false;
329  QString msg;
330 
331  QString desc = m_descriptionEdit->GetText();
332 
333  if (desc.contains(RecordingInfo::kReLeadingAnd))
334  {
335  msg = "Power Priority rules do not reqiure a leading \"AND\"";
336  }
337  else if (desc.contains(';'))
338  {
339  msg = "Power Priority rules cannot include semicolon ( ; ) ";
340  msg += "statement terminators.";
341  }
342  else
343  {
344  QString qstr = QString("SELECT (%1) FROM (recordmatch, record, "
345  "program, channel, capturecard, "
346  "oldrecorded) WHERE NULL").arg(desc);
347  while (true)
348  {
349  int i = qstr.indexOf("RECTABLE");
350  if (i == -1) break;
351  qstr = qstr.replace(i, strlen("RECTABLE"), "record");
352  }
353 
354  MSqlQuery query(MSqlQuery::InitCon());
355  query.prepare(qstr);
356 
357  if (query.exec())
358  {
359  ret = true;
360  }
361  else
362  {
363  msg = tr("An error was found when checking") + ":\n\n";
364  msg += query.executedQuery();
365  msg += "\n\n" + tr("The database error was") + ":\n";
366  msg += query.lastError().databaseText();
367  ret = false;
368  }
369  }
370 
371  if (!msg.isEmpty())
372  ShowOkPopup(msg);
373 
374  return ret;
375 }
376 
378 {
380  if (!item)
381  return;
382 
383  QString ttable = "powerpriority_tmp";
384 
386  MSqlQuery query(dbcon);
387  QString thequery;
388 
389  thequery = "SELECT GET_LOCK(:LOCK, 2);";
390  query.prepare(thequery);
391  query.bindValue(":LOCK", "DiffSchedule");
392  if (!query.exec())
393  {
394  QString msg =
395  QString("DB Error (Obtaining lock in testRecording): \n"
396  "Query was: %1 \nError was: %2 \n")
397  .arg(thequery,
399  LOG(VB_GENERAL, LOG_ERR, msg);
400  return;
401  }
402 
403  thequery = QString("DROP TABLE IF EXISTS %1;").arg(ttable);
404  query.prepare(thequery);
405  if (!query.exec())
406  {
407  QString msg =
408  QString("DB Error (deleting old table in testRecording): \n"
409  "Query was: %1 \nError was: %2 \n")
410  .arg(thequery,
412  LOG(VB_GENERAL, LOG_ERR, msg);
413  return;
414  }
415 
416  thequery = QString("CREATE TABLE %1 SELECT * FROM powerpriority;")
417  .arg(ttable);
418  query.prepare(thequery);
419  if (!query.exec())
420  {
421  QString msg =
422  QString("DB Error (create new table): \n"
423  "Query was: %1 \nError was: %2 \n")
424  .arg(thequery,
426  LOG(VB_GENERAL, LOG_ERR, msg);
427  return;
428  }
429 
430  query.prepare(QString("DELETE FROM %1 WHERE priorityname = :NAME;")
431  .arg(ttable));
432  query.bindValue(":NAME", m_titleEdit->GetText());
433 
434  if (!query.exec())
435  MythDB::DBError("Test power search delete", query);
436 
437  thequery = QString("INSERT INTO %1 "
438  "(priorityname, recpriority, selectclause) "
439  "VALUES(:NAME,:VALUE,:CLAUSE);").arg(ttable);
440  query.prepare(thequery);
441  query.bindValue(":NAME", m_titleEdit->GetText());
442  query.bindValue(":VALUE", item->GetText());
443  query.bindValue(":CLAUSE", m_descriptionEdit->GetText());
444 
445  if (!query.exec())
446  MythDB::DBError("Test power search insert", query);
447 
448  QString ltitle = tr("Power Priority");
449  if (!m_titleEdit->GetText().isEmpty())
450  ltitle = m_titleEdit->GetText();
451 
453  auto *vsd = new ViewScheduleDiff(mainStack, ttable, 0, ltitle);
454 
455  if (vsd->Create())
456  mainStack->AddScreen(vsd);
457  else
458  delete vsd;
459 
460  thequery = "SELECT RELEASE_LOCK(:LOCK);";
461  query.prepare(thequery);
462  query.bindValue(":LOCK", "DiffSchedule");
463  if (!query.exec())
464  {
465  QString msg =
466  QString("DB Error (free lock): \n"
467  "Query was: %1 \nError was: %2 \n")
468  .arg(thequery,
470  LOG(VB_GENERAL, LOG_ERR, msg);
471  }
472 }
MythUIButton::Clicked
void Clicked()
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
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:127
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:318
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:1591
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:326
CustomPriority::addClicked
void addClicked(void)
Definition: custompriority.cpp:251
RuleInfo::description
QString description
Definition: custompriority.h:59
mythdb.h
MythDB::DBErrorMessage
static QString DBErrorMessage(const QSqlError &err)
Definition: mythdb.cpp:231
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:135
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
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:619
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:129
mythlogging.h
MSqlQueryInfo
MSqlDatabase Info, used by MSqlQuery. Do not use directly.
Definition: mythdbcon.h:92
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:551
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:361
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
custompriority.h
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:206
CustomPriority::deleteClicked
void deleteClicked(void)
Definition: custompriority.cpp:308
CustomPriority::testSchedule
void testSchedule(void)
Definition: custompriority.cpp:377
CustomPriority::loadExampleRules
void loadExampleRules(void)
Definition: custompriority.cpp:149
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:581
scheduledrecording.h
MythUIType::SetEnabled
void SetEnabled(bool enable)
Definition: mythuitype.cpp:1133
CustomPriority::CustomPriority
CustomPriority(MythScreenStack *parent, ProgramInfo *proginfo=nullptr)
Definition: custompriority.cpp:21
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3660
CustomPriority::textChanged
void textChanged()
Definition: custompriority.cpp:242
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
CustomPriority::ruleChanged
void ruleChanged(MythUIButtonListItem *item)
Definition: custompriority.cpp:227
ScheduledRecording::ReschedulePlace
static void ReschedulePlace(const QString &why)
Definition: scheduledrecording.h:33
channelutil.h
MSqlQuery::lastError
QSqlError lastError(void) const
Definition: mythdbcon.h:213
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:269
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:205
mythuitextedit.h
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:687
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
CustomPriority::m_installButton
MythUIButton * m_installButton
Definition: custompriority.h:51
CustomPriority::installClicked
void installClicked(void)
Definition: custompriority.cpp:277
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
MythUIButtonList::SetItemCurrent
void SetItemCurrent(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1558
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:52
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:838