Go to the documentation of this file.
32 m_seSuffix = QString(
" (%1)").arg(tr(
"stored search"));
33 m_exSuffix = QString(
" (%1)").arg(tr(
"stored example"));
65 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'customedit'");
106 quoteTitle.replace(
"\'",
"\'\'");
107 rule.
description = QString(
"program.title = '%1' ").arg(quoteTitle);
111 QVariant::fromValue(rule));
114 result.
prepare(
"SELECT recordid, title, subtitle, description "
115 "FROM record WHERE search = :SEARCH ORDER BY title;");
121 while (result.
next())
123 QString trimTitle = result.
value(1).toString();
127 rule.
title = trimTitle;
134 QVariant::fromValue(rule));
153 static const QRegularExpression replacement {
"\\{([A-Z]+)\\}" };
156 QRegularExpressionMatch match;
157 if (!clause.contains(replacement, &match))
160 QString mid = match.captured(1);
163 if (mid.compare(
"TITLE") == 0) {
165 repl.replace(
"\'",
"\'\'");
166 }
else if (mid.compare(
"SUBTITLE") == 0) {
168 repl.replace(
"\'",
"\'\'");
169 }
else if (mid.compare(
"DESCR") == 0) {
171 repl.replace(
"\'",
"\'\'");
172 }
else if (mid.compare(
"SERIESID") == 0) {
174 }
else if (mid.compare(
"PROGID") == 0) {
176 }
else if (mid.compare(
"SEASON") == 0) {
178 }
else if (mid.compare(
"EPISODE") == 0) {
180 }
else if (mid.compare(
"CATEGORY") == 0) {
182 }
else if (mid.compare(
"CHANID") == 0) {
184 }
else if (mid.compare(
"CHANNUM") == 0) {
186 }
else if (mid.compare(
"SCHEDID") == 0) {
188 }
else if (mid.compare(
"CHANNAME") == 0) {
190 }
else if (mid.compare(
"DAYNAME") == 0) {
192 }
else if (mid.compare(
"STARTDATE") == 0) {
194 }
else if (mid.compare(
"ENDDATE") == 0) {
196 }
else if (mid.compare(
"STARTTIME") == 0) {
198 }
else if (mid.compare(
"ENDTIME") == 0) {
200 }
else if (mid.compare(
"STARTSEC") == 0) {
202 QDateTime midnight = date.date().startOfDay();
203 repl = QString(
"%1").arg(midnight.secsTo(date));
204 }
else if (mid.compare(
"ENDSEC") == 0) {
206 QDateTime midnight = date.date().startOfDay();
207 repl = QString(
"%1").arg(midnight.secsTo(date));
210 clause.replace(match.capturedStart(), match.capturedLength(), repl);
219 rule.
title = tr(
"Match an exact title");
221 rule.
description = QString(
"program.title = '{TITLE}' ");
225 QVariant::fromValue(rule));
229 rule.
title = tr(
"Match this series");
231 rule.
description = QString(
"program.seriesid = '{SERIESID}' ");
233 QVariant::fromValue(rule));
236 rule.
title = tr(
"Match words in the title");
239 rule.
description = QString(
"program.title LIKE '%{TITLE}%' ");
243 QVariant::fromValue(rule));
245 rule.
title = tr(
"Match words in the subtitle");
248 rule.
description = QString(
"program.subtitle LIKE '%{SUBTITLE}%' ");
250 rule.
description =
"program.subtitle LIKE '%Las Vegas%' ";
252 QVariant::fromValue(rule));
256 rule.
title = tr(
"Match this episode");
258 rule.
description = QString(
"program.programid = '{PROGID}' ");
262 rule.
title = tr(
"Match this episode");
264 rule.
description = QString(
"program.subtitle = '{SUBTITLE}' \n"
265 "AND program.description = '{DESCR}' ");
269 rule.
title = tr(
"Match an exact episode");
271 rule.
description = QString(
"program.title = 'Seinfeld' \n"
272 "AND program.subtitle = 'The Soup' ");
275 QVariant::fromValue(rule));
277 rule.
title = tr(
"Match in any descriptive field");
279 rule.
description = QString(
"(program.title LIKE '%Japan%' \n"
280 " OR program.subtitle LIKE '%Japan%' \n"
281 " OR program.description LIKE '%Japan%') ");
283 QVariant::fromValue(rule));
285 rule.
title = tr(
"New episodes only");
289 QVariant::fromValue(rule));
291 rule.
title = tr(
"Exclude unidentified episodes");
295 QVariant::fromValue(rule));
297 rule.
title = tr(
"First showing of each episode");
301 QVariant::fromValue(rule));
303 rule.
title = tr(
"Last showing of each episode");
307 QVariant::fromValue(rule));
309 rule.
title = tr(
"Anytime on a specific day of the week");
312 "DAYNAME(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) = '{DAYNAME}' ";
314 QVariant::fromValue(rule));
316 rule.
title = tr(
"Only on weekdays (Monday through Friday)");
319 "WEEKDAY(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) < 5 ";
321 QVariant::fromValue(rule));
323 rule.
title = tr(
"Only on weekends");
326 "WEEKDAY(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) >= 5 ";
328 QVariant::fromValue(rule));
330 rule.
title = tr(
"Only in prime time");
333 "HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) >= 19 "
334 "AND HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) < 23 ";
336 QVariant::fromValue(rule));
338 rule.
title = tr(
"Not in prime time");
341 "(HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) < 19 "
342 " OR HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) >= 23) ";
344 QVariant::fromValue(rule));
346 rule.
title = tr(
"Only on a specific station");
349 rule.
description = QString(
"channel.callsign = '{SCHEDID}' ");
353 QVariant::fromValue(rule));
355 rule.
title = tr(
"Exclude one station");
359 QVariant::fromValue(rule));
361 rule.
title = tr(
"Match related callsigns");
363 rule.
description =
"channel.callsign LIKE 'HBO%' ";
365 QVariant::fromValue(rule));
367 rule.
title = tr(
"Only channels from the Favorites group");
368 rule.
subtitle =
", channelgroup cg, channelgroupnames cgn";
370 "AND cg.grpid = cgn.grpid \n"
371 "AND program.chanid = cg.chanid ";
373 QVariant::fromValue(rule));
375 rule.
title = tr(
"Only channels from a specific video source");
379 QVariant::fromValue(rule));
381 rule.
title = tr(
"Only channels marked as commercial free");
383 rule.
description = QString(
"channel.commmethod = %1 ")
386 QVariant::fromValue(rule));
388 rule.
title = tr(
"Only shows marked as HDTV");
392 QVariant::fromValue(rule));
394 rule.
title = tr(
"Only shows marked as widescreen");
396 rule.
description =
"FIND_IN_SET('WIDESCREEN', program.videoprop) > 0 ";
398 QVariant::fromValue(rule));
400 rule.
title = tr(
"Exclude H.264 encoded streams (EIT only)");
402 rule.
description =
"FIND_IN_SET('AVC', program.videoprop) = 0 ";
404 QVariant::fromValue(rule));
406 rule.
title = tr(
"Only shows with in-vision signing");
408 rule.
description =
"FIND_IN_SET('SIGNED', program.subtitletypes) > 0 ";
410 QVariant::fromValue(rule));
412 rule.
title = tr(
"Only shows with in-vision subtitles");
414 rule.
description =
"FIND_IN_SET('ONSCREEN', program.subtitletypes) > 0 ";
416 QVariant::fromValue(rule));
418 rule.
title = tr(
"Limit by category");
421 rule.
description = QString(
"program.category = '{CATEGORY}' ");
423 rule.
description =
"program.category = 'Reality' ";
425 QVariant::fromValue(rule));
427 rule.
title = tr(
"All matches for a genre (Schedules Direct)");
428 rule.
subtitle =
"LEFT JOIN programgenres ON "
429 "program.chanid = programgenres.chanid AND "
430 "program.starttime = programgenres.starttime ";
432 rule.
description = QString(
"programgenres.genre = '{CATEGORY}' ");
434 rule.
description =
"programgenres.genre = 'Reality' ";
436 QVariant::fromValue(rule));
438 rule.
title = tr(
"Limit by MPAA or VCHIP rating (Schedules Direct)");
439 rule.
subtitle =
"LEFT JOIN programrating ON "
440 "program.chanid = programrating.chanid AND "
441 "program.starttime = programrating.starttime ";
442 rule.
description =
"(programrating.rating = 'G' OR programrating.rating "
445 QVariant::fromValue(rule));
447 rule.
title = tr(
"Category type (%1)",
"List of hardcoded category types")
448 .arg(
"'movie', 'series', 'sports', 'tvshow'");
450 rule.
description =
"program.category_type = 'sports' ";
452 QVariant::fromValue(rule));
454 rule.
title = tr(
"Limit movies by the year of release");
456 rule.
description =
"program.category_type = 'movie' AND "
457 "program.airdate >= 2000 ";
459 QVariant::fromValue(rule));
461 rule.
title = tr(
"Minimum star rating (0.0 to 1.0 for movies only)");
465 QVariant::fromValue(rule));
467 rule.
title = tr(
"Person named in the credits (Schedules Direct)");
468 rule.
subtitle =
", people, credits";
470 "AND credits.person = people.person \n"
471 "AND program.chanid = credits.chanid \n"
472 "AND program.starttime = credits.starttime ";
474 QVariant::fromValue(rule));
488 rule.
title = tr(
"Re-record SDTV in HDTV (disable duplicate matching)");
489 rule.
subtitle =
", recordedprogram rp1 LEFT OUTER JOIN recordedprogram rp2"
490 " ON rp1.programid = rp2.programid AND rp2.hdtv = 1";
491 rule.
description =
"program.programid = rp1.programid \n"
492 "AND rp1.hdtv = 0 \n"
493 "AND program.hdtv = 1 \n"
494 "AND rp2.starttime IS NULL ";
496 QVariant::fromValue(rule));
498 rule.
title = tr(
"Multiple sports teams (complete example)");
500 rule.
description =
"program.title = 'NBA Basketball' \n"
501 "AND program.subtitle REGEXP '(Miami|Cavaliers|Lakers)' \n"
502 "AND program.first > 0 \n";
504 QVariant::fromValue(rule));
506 rule.
title = tr(
"Sci-fi B-movies (complete example)");
508 rule.
description =
"program.category_type='movie' \n"
509 "AND program.category='Science fiction' \n"
510 "AND program.stars <= 0.5 AND program.airdate < 1970 ";
512 QVariant::fromValue(rule));
515 tr(
"SportsCenter Overnight (complete example - use FindDaily)");
518 "program.title = 'SportsCenter' \n"
519 "AND HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) >= 2 \n"
520 "AND HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) <= 6 ";
522 QVariant::fromValue(rule));
524 rule.
title = tr(
"Movie of the Week (complete example - use FindWeekly)");
527 "program.category_type='movie' \n"
528 "AND program.stars >= 1.0 AND program.airdate >= 1965 \n"
529 "AND DAYNAME(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) = 'Friday' \n"
530 "AND HOUR(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) >= 12 ";
532 QVariant::fromValue(rule));
534 rule.
title = tr(
"First Episodes (complete example for Schedules Direct)");
537 "AND program.programid LIKE 'EP%0001' \n"
538 "AND program.originalairdate = "
539 "DATE(CONVERT_TZ(program.starttime, 'Etc/UTC', 'SYSTEM')) ";
541 QVariant::fromValue(rule));
546 result.
prepare(
"SELECT rulename,fromclause,whereclause,search "
547 "FROM customexample;");
551 while (result.
next())
553 QString str = result.
value(0).toString();
555 if (result.
value(3).toInt() > 0)
564 QVariant::fromValue(rule));
593 (hastitle && hasdesc));
604 msg = QString(
"\"%1\"").arg(msg.simplified());
611 (hastitle && hasdesc));
624 static const QRegularExpression kNonWhitespaceRE {
"\\S" };
625 if (desc.contains(kNonWhitespaceRE))
679 int cur_recid = rule.
recordid.toInt();
696 if (schededit->Create())
715 bool exampleExists =
false;
718 query.
prepare(
"SELECT rulename,whereclause FROM customexample "
719 "WHERE rulename = :RULE;");
723 exampleExists =
true;
725 QString msg = QString(
"%1: %2\n\n").arg(tr(
"Current Example"),
734 auto *storediag =
new MythDialogBox(msg, mainStack,
"storePopup",
true);
736 storediag->SetReturnEvent(
this,
"storeruledialog");
737 if (storediag->Create())
744 str = tr(
"Replace as a search");
746 str = tr(
"Store as a search");
747 storediag->AddButton(str);
750 str = tr(
"Replace as an example");
752 str = tr(
"Store as an example");
753 storediag->AddButton(str);
759 QString str = QString(
"%1 \"%2\"").arg(tr(
"Delete"),
761 storediag->AddButton(str);
781 msg = tr(
"Power Search rules no longer require a leading \"AND\".");
783 else if (desc.contains(
';'))
785 msg = tr(
"Power Search rules cannot include semicolon ( ; ) ");
786 msg += tr(
"statement terminators.");
791 query.
prepare(QString(
"SELECT NULL FROM (program, channel, oldrecorded AS oldrecstatus) "
792 "%1 WHERE %2 LIMIT 5").arg(from, desc));
800 msg = tr(
"An error was found when checking") +
":\n\n";
802 msg +=
"\n\n" + tr(
"The database error was") +
":\n";
810 GetStack(
"popup stack");
811 auto *checkSyntaxPopup =
814 if (checkSyntaxPopup->Create())
816 checkSyntaxPopup->SetReturnEvent(
this,
"checkSyntaxPopup");
821 delete checkSyntaxPopup;
837 query.
prepare(
"REPLACE INTO customexample "
838 "(rulename,fromclause,whereclause,search) "
839 "VALUES(:RULE,:FROMC,:WHEREC,:SEARCH);");
855 QVariant::fromValue(rule));
869 item->
SetData(QVariant::fromValue(rule));
886 query.
prepare(
"DELETE FROM customexample "
887 "WHERE rulename = :RULE;");
905 QString resultid = dce->GetId();
906 QString resulttext = dce->GetResultText();
908 if (resultid ==
"storeruledialog")
910 if (resulttext.startsWith(tr(
"Delete")))
914 else if (!resulttext.isEmpty())
916 storeRule(resulttext.contains(tr(
"as a search")),
917 !resulttext.startsWith(tr(
"Replace")));
931 for (
int i = 0; i < actions.size() && !handled; i++)
933 const QString&
action = actions[i];
943 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