Go to the documentation of this file.
31 m_seSuffix = QString(
" (%1)").arg(tr(
"stored search"));
32 m_exSuffix = QString(
" (%1)").arg(tr(
"stored example"));
64 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'customedit'");
105 quoteTitle.replace(
"\'",
"\'\'");
106 rule.
description = QString(
"program.title = '%1' ").arg(quoteTitle);
110 QVariant::fromValue(rule));
113 result.
prepare(
"SELECT recordid, title, subtitle, description "
114 "FROM record WHERE search = :SEARCH ORDER BY title;");
120 while (result.
next())
122 QString trimTitle = result.
value(1).toString();
126 rule.
title = trimTitle;
133 QVariant::fromValue(rule));
150 static const QRegularExpression replacement {
"\\{([A-Z]+)\\}" };
153 QRegularExpressionMatch match;
154 if (!clause.contains(replacement, &match))
157 QString mid = match.captured(1);
160 if (mid.compare(
"TITLE") == 0) {
162 repl.replace(
"\'",
"\'\'");
163 }
else if (mid.compare(
"SUBTITLE") == 0) {
165 repl.replace(
"\'",
"\'\'");
166 }
else if (mid.compare(
"DESCR") == 0) {
168 repl.replace(
"\'",
"\'\'");
169 }
else if (mid.compare(
"SERIESID") == 0) {
171 }
else if (mid.compare(
"PROGID") == 0) {
173 }
else if (mid.compare(
"SEASON") == 0) {
175 }
else if (mid.compare(
"EPISODE") == 0) {
177 }
else if (mid.compare(
"CATEGORY") == 0) {
179 }
else if (mid.compare(
"CHANID") == 0) {
181 }
else if (mid.compare(
"CHANNUM") == 0) {
183 }
else if (mid.compare(
"SCHEDID") == 0) {
185 }
else if (mid.compare(
"CHANNAME") == 0) {
187 }
else if (mid.compare(
"DAYNAME") == 0) {
189 }
else if (mid.compare(
"STARTDATE") == 0) {
191 }
else if (mid.compare(
"ENDDATE") == 0) {
193 }
else if (mid.compare(
"STARTTIME") == 0) {
195 }
else if (mid.compare(
"ENDTIME") == 0) {
197 }
else if (mid.compare(
"STARTSEC") == 0) {
199 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
200 QDateTime midnight = QDateTime(date.date());
202 QDateTime midnight = date.date().startOfDay();
204 repl = QString(
"%1").arg(midnight.secsTo(date));
205 }
else if (mid.compare(
"ENDSEC") == 0) {
207 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
208 QDateTime midnight = QDateTime(date.date());
210 QDateTime midnight = date.date().startOfDay();
212 repl = QString(
"%1").arg(midnight.secsTo(date));
215 clause.replace(match.capturedStart(), match.capturedLength(), repl);
224 rule.
title = tr(
"Match an exact title");
226 rule.
description = QString(
"program.title = '{TITLE}' ");
230 QVariant::fromValue(rule));
234 rule.
title = tr(
"Match this series");
236 rule.
description = QString(
"program.seriesid = '{SERIESID}' ");
238 QVariant::fromValue(rule));
241 rule.
title = tr(
"Match words in the title");
244 rule.
description = QString(
"program.title LIKE '%{TITLE}%' ");
248 QVariant::fromValue(rule));
250 rule.
title = tr(
"Match words in the subtitle");
253 rule.
description = QString(
"program.subtitle LIKE '%{SUBTITLE}%' ");
255 rule.
description =
"program.subtitle LIKE '%Las Vegas%' ";
257 QVariant::fromValue(rule));
261 rule.
title = tr(
"Match this episode");
263 rule.
description = QString(
"program.programid = '{PROGID}' ");
267 rule.
title = tr(
"Match this episode");
269 rule.
description = QString(
"program.subtitle = '{SUBTITLE}' \n"
270 "AND program.description = '{DESCR}' ");
274 rule.
title = tr(
"Match an exact episode");
276 rule.
description = QString(
"program.title = 'Seinfeld' \n"
277 "AND program.subtitle = 'The Soup' ");
280 QVariant::fromValue(rule));
282 rule.
title = tr(
"Match in any descriptive field");
284 rule.
description = QString(
"(program.title LIKE '%Japan%' \n"
285 " OR program.subtitle LIKE '%Japan%' \n"
286 " OR program.description LIKE '%Japan%') ");
288 QVariant::fromValue(rule));
290 rule.
title = tr(
"New episodes only");
294 QVariant::fromValue(rule));
296 rule.
title = tr(
"Exclude unidentified episodes");
300 QVariant::fromValue(rule));
302 rule.
title = tr(
"First showing of each episode");
306 QVariant::fromValue(rule));
308 rule.
title = tr(
"Last showing of each episode");
312 QVariant::fromValue(rule));
314 rule.
title = tr(
"Anytime on a specific day of the week");
317 "DAYNAME(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) = '{DAYNAME}' ";
319 QVariant::fromValue(rule));
321 rule.
title = tr(
"Only on weekdays (Monday through Friday)");
324 "WEEKDAY(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) < 5 ";
326 QVariant::fromValue(rule));
328 rule.
title = tr(
"Only on weekends");
331 "WEEKDAY(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) >= 5 ";
333 QVariant::fromValue(rule));
335 rule.
title = tr(
"Only in prime time");
338 "HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) >= 19 "
339 "AND HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) < 23 ";
341 QVariant::fromValue(rule));
343 rule.
title = tr(
"Not in prime time");
346 "(HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) < 19 "
347 " OR HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) >= 23) ";
349 QVariant::fromValue(rule));
351 rule.
title = tr(
"Only on a specific station");
354 rule.
description = QString(
"channel.callsign = '{SCHEDID}' ");
358 QVariant::fromValue(rule));
360 rule.
title = tr(
"Exclude one station");
364 QVariant::fromValue(rule));
366 rule.
title = tr(
"Match related callsigns");
368 rule.
description =
"channel.callsign LIKE 'HBO%' ";
370 QVariant::fromValue(rule));
372 rule.
title = tr(
"Only channels from the Favorites group");
373 rule.
subtitle =
", channelgroup cg, channelgroupnames cgn";
375 "AND cg.grpid = cgn.grpid \n"
376 "AND program.chanid = cg.chanid ";
378 QVariant::fromValue(rule));
380 rule.
title = tr(
"Only channels from a specific video source");
384 QVariant::fromValue(rule));
386 rule.
title = tr(
"Only channels marked as commercial free");
388 rule.
description = QString(
"channel.commmethod = %1 ")
391 QVariant::fromValue(rule));
393 rule.
title = tr(
"Only shows marked as HDTV");
397 QVariant::fromValue(rule));
399 rule.
title = tr(
"Only shows marked as widescreen");
401 rule.
description =
"FIND_IN_SET('WIDESCREEN', program.videoprop) > 0 ";
403 QVariant::fromValue(rule));
405 rule.
title = tr(
"Exclude H.264 encoded streams (EIT only)");
407 rule.
description =
"FIND_IN_SET('AVC', program.videoprop) = 0 ";
409 QVariant::fromValue(rule));
411 rule.
title = tr(
"Only shows with in-vision signing");
413 rule.
description =
"FIND_IN_SET('SIGNED', program.subtitletypes) > 0 ";
415 QVariant::fromValue(rule));
417 rule.
title = tr(
"Only shows with in-vision subtitles");
419 rule.
description =
"FIND_IN_SET('ONSCREEN', program.subtitletypes) > 0 ";
421 QVariant::fromValue(rule));
423 rule.
title = tr(
"Limit by category");
426 rule.
description = QString(
"program.category = '{CATEGORY}' ");
428 rule.
description =
"program.category = 'Reality' ";
430 QVariant::fromValue(rule));
432 rule.
title = tr(
"All matches for a genre (Schedules Direct)");
433 rule.
subtitle =
"LEFT JOIN programgenres ON "
434 "program.chanid = programgenres.chanid AND "
435 "program.starttime = programgenres.starttime ";
437 rule.
description = QString(
"programgenres.genre = '{CATEGORY}' ");
439 rule.
description =
"programgenres.genre = 'Reality' ";
441 QVariant::fromValue(rule));
443 rule.
title = tr(
"Limit by MPAA or VCHIP rating (Schedules Direct)");
444 rule.
subtitle =
"LEFT JOIN programrating ON "
445 "program.chanid = programrating.chanid AND "
446 "program.starttime = programrating.starttime ";
447 rule.
description =
"(programrating.rating = 'G' OR programrating.rating "
450 QVariant::fromValue(rule));
452 rule.
title = tr(
"Category type (%1)",
"List of hardcoded category types")
453 .arg(
"'movie', 'series', 'sports', 'tvshow'");
455 rule.
description =
"program.category_type = 'sports' ";
457 QVariant::fromValue(rule));
459 rule.
title = tr(
"Limit movies by the year of release");
461 rule.
description =
"program.category_type = 'movie' AND "
462 "program.airdate >= 2000 ";
464 QVariant::fromValue(rule));
466 rule.
title = tr(
"Minimum star rating (0.0 to 1.0 for movies only)");
470 QVariant::fromValue(rule));
472 rule.
title = tr(
"Person named in the credits (Schedules Direct)");
473 rule.
subtitle =
", people, credits";
475 "AND credits.person = people.person \n"
476 "AND program.chanid = credits.chanid \n"
477 "AND program.starttime = credits.starttime ";
479 QVariant::fromValue(rule));
493 rule.
title = tr(
"Re-record SDTV in HDTV (disable duplicate matching)");
494 rule.
subtitle =
", recordedprogram rp1 LEFT OUTER JOIN recordedprogram rp2"
495 " ON rp1.programid = rp2.programid AND rp2.hdtv = 1";
496 rule.
description =
"program.programid = rp1.programid \n"
497 "AND rp1.hdtv = 0 \n"
498 "AND program.hdtv = 1 \n"
499 "AND rp2.starttime IS NULL ";
501 QVariant::fromValue(rule));
503 rule.
title = tr(
"Multiple sports teams (complete example)");
505 rule.
description =
"program.title = 'NBA Basketball' \n"
506 "AND program.subtitle REGEXP '(Miami|Cavaliers|Lakers)' \n"
507 "AND program.first > 0 \n";
509 QVariant::fromValue(rule));
511 rule.
title = tr(
"Sci-fi B-movies (complete example)");
513 rule.
description =
"program.category_type='movie' \n"
514 "AND program.category='Science fiction' \n"
515 "AND program.stars <= 0.5 AND program.airdate < 1970 ";
517 QVariant::fromValue(rule));
520 tr(
"SportsCenter Overnight (complete example - use FindDaily)");
523 "program.title = 'SportsCenter' \n"
524 "AND HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) >= 2 \n"
525 "AND HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) <= 6 ";
527 QVariant::fromValue(rule));
529 rule.
title = tr(
"Movie of the Week (complete example - use FindWeekly)");
532 "program.category_type='movie' \n"
533 "AND program.stars >= 1.0 AND program.airdate >= 1965 \n"
534 "AND DAYNAME(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) = 'Friday' \n"
535 "AND HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) >= 12 ";
537 QVariant::fromValue(rule));
539 rule.
title = tr(
"First Episodes (complete example for Schedules Direct)");
542 "AND program.programid LIKE 'EP%0001' \n"
543 "AND program.originalairdate = "
544 "DATE(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) ";
546 QVariant::fromValue(rule));
551 result.
prepare(
"SELECT rulename,fromclause,whereclause,search "
552 "FROM customexample;");
556 while (result.
next())
558 QString str = result.
value(0).toString();
560 if (result.
value(3).toInt() > 0)
569 QVariant::fromValue(rule));
598 (hastitle && hasdesc));
609 msg = QString(
"\"%1\"").arg(msg.simplified());
616 (hastitle && hasdesc));
629 static const QRegularExpression kNonWhitespaceRE {
"\\S" };
630 if (desc.contains(kNonWhitespaceRE))
682 int cur_recid = rule.
recordid.toInt();
699 if (schededit->Create())
716 bool exampleExists =
false;
719 query.
prepare(
"SELECT rulename,whereclause FROM customexample "
720 "WHERE rulename = :RULE;");
724 exampleExists =
true;
726 QString msg = QString(
"%1: %2\n\n").arg(tr(
"Current Example"),
735 auto *storediag =
new MythDialogBox(msg, mainStack,
"storePopup",
true);
737 storediag->SetReturnEvent(
this,
"storeruledialog");
738 if (storediag->Create())
745 str = tr(
"Replace as a search");
747 str = tr(
"Store as a search");
748 storediag->AddButton(str);
751 str = tr(
"Replace as an example");
753 str = tr(
"Store as an example");
754 storediag->AddButton(str);
760 QString str = QString(
"%1 \"%2\"").arg(tr(
"Delete"),
762 storediag->AddButton(str);
780 msg = tr(
"Power Search rules no longer require a leading \"AND\".");
782 else if (desc.contains(
';'))
784 msg = tr(
"Power Search rules cannot include semicolon ( ; ) ");
785 msg += tr(
"statement terminators.");
790 query.
prepare(QString(
"SELECT NULL FROM (program, channel, oldrecorded AS oldrecstatus) "
791 "%1 WHERE %2 LIMIT 5").arg(from, desc));
799 msg = tr(
"An error was found when checking") +
":\n\n";
801 msg +=
"\n\n" + tr(
"The database error was") +
":\n";
809 GetStack(
"popup stack");
810 auto *checkSyntaxPopup =
813 if (checkSyntaxPopup->Create())
815 checkSyntaxPopup->SetReturnEvent(
this,
"checkSyntaxPopup");
820 delete checkSyntaxPopup;
836 query.
prepare(
"REPLACE INTO customexample "
837 "(rulename,fromclause,whereclause,search) "
838 "VALUES(:RULE,:FROMC,:WHEREC,:SEARCH);");
854 QVariant::fromValue(rule));
868 item->
SetData(QVariant::fromValue(rule));
885 query.
prepare(
"DELETE FROM customexample "
886 "WHERE rulename = :RULE;");
904 QString resultid = dce->GetId();
905 QString resulttext = dce->GetResultText();
907 if (resultid ==
"storeruledialog")
909 if (resulttext.startsWith(tr(
"Delete")))
913 else if (!resulttext.isEmpty())
915 storeRule(resulttext.contains(tr(
"as a search")),
916 !resulttext.startsWith(tr(
"Replace")));
930 for (
int i = 0; i < actions.size() && !handled; i++)
932 QString
action = actions[i];
942 else if (
action ==
"EDIT")
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
MythScreenStack * GetMainStack()
void SetMaxLength(int length)
MythUIButtonList * m_ruleList
static const QRegularExpression kReSearchTypeName
void storeRule(bool is_search, bool is_new)
void ruleChanged(MythUIButtonListItem *item)
const MythUIButtonListItem * m_currentRuleItem
void clauseChanged(MythUIButtonListItem *item)
QString GetChannelName(void) const
This is the channel name in the local market, i.e.
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
QVariant value(int i) const
QString GetChannelSchedulingID(void) const
This is the unique programming identifier of a channel.
QString GetCategory(void) const
static const QRegularExpression kReLeadingAnd
Internal representation of a recording rule, mirrors the record table.
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
~CustomEdit(void) override
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Screen in which all other widgets are contained and rendered.
MythUITextEdit * m_descriptionEdit
void ruleSaved(int ruleId)
QString GetText(void) const
void customEvent(QEvent *event) override
MythUIText * m_clauseText
MythUIType * GetFocusWidget(void) const
MythUITextEdit * m_titleEdit
void addListener(QObject *listener)
Add a listener to the observable.
CustomEdit(MythScreenStack *parent, ProgramInfo *m_pginfo=nullptr)
void SetText(const QString &text, bool moveCursor=true)
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
Basic menu dialog, message and a list of options.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
QString GetTitle(void) const
QString GetDescription(void) const
static void DBError(const QString &where, const MSqlQuery &query)
void BuildFocusList(void)
MythUIButton * m_testButton
void SetEnabled(bool enable)
MythUIButton * m_cancelButton
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
QString GetSeriesID(void) const
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
QSqlError lastError(void) const
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
uint GetEpisode(void) const
Holds information on recordings and videos.
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Dialog asking for user confirmation. Ok and optional Cancel button.
uint GetSeason(void) const
QString executedQuery(void) const
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
MythUIButton * m_storeButton
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
void clauseClicked(MythUIButtonListItem *item)
virtual void SetText(const QString &text)
static const Type kEventType
MythMainWindow * GetMythMainWindow(void)
void recordClicked(void)
The user clicked on the 'Record' button in the 'Custom Edit' window.
QString GetProgramID(void) const
uint GetRecordingRuleID(void) const
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Construct a recording schedule.
QString evaluate(QString clause)
void removeListener(QObject *listener)
Remove a listener to the observable.
MythUIButtonList * m_clauseList
MythUITextEdit * m_subtitleEdit
MythUIButton * m_recordButton
void scheduleCreated(int ruleID)
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
QString GetSubtitle(void) const