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