MythTV master
schedulecommon.cpp
Go to the documentation of this file.
1// Qt
2#include <QCoreApplication>
3
4// MythTV
15
16// MythFrontend
17#include "customedit.h"
18#include "guidegrid.h"
19#include "prevreclist.h"
20#include "progdetails.h"
21#include "proglist.h"
22#include "schedulecommon.h"
23#include "scheduleeditor.h"
24
29{
31 if (!pginfo)
32 return;
33
35 auto *details_dialog = new ProgDetails(mainStack, pginfo);
36
37 if (!details_dialog->Create())
38 {
39 delete details_dialog;
40 return;
41 }
42
43 mainStack->AddScreen(details_dialog);
44}
45
49void ScheduleCommon::ShowUpcoming(const QString &title,
50 const QString &seriesid)
51{
52 if (title.isEmpty())
53 return;
54
56 auto *pl = new ProgLister(mainStack, plTitle, title, seriesid);
57 if (pl->Create())
58 {
59 mainStack->AddScreen(pl);
60 }
61 else
62 {
63 delete pl;
64 }
65}
66
71{
73 if (!pginfo)
74 return;
75
76 if (pginfo->GetChanID() == 0 &&
77 pginfo->GetRecordingRuleID() > 0)
78 {
80 return;
81 }
82
83 ShowUpcoming(pginfo->GetTitle(), pginfo->GetSeriesID());
84}
85
90{
92 if (!pginfo)
93 return;
94
95 RecordingInfo ri(*pginfo);
96
97 uint id = ri.GetRecordingRuleID();
98 if (id == 0)
99 {
100 ShowUpcoming(pginfo->GetTitle(), pginfo->GetSeriesID());
101 return;
102 }
103
105 auto *pl = new ProgLister(mainStack, plRecordid, QString::number(id), "");
106
107 if (pl->Create())
108 mainStack->AddScreen(pl);
109 else
110 delete pl;
111}
112
117{
118 ProgramInfo *pginfo = GetCurrentProgram();
119 if (!pginfo)
120 return;
121
123 auto *pl = new ProgLister(mainStack, plChannel,
124 QString::number(pginfo->GetChanID()), "",
125 pginfo->GetScheduledStartTime());
126 if (pl->Create())
127 mainStack->AddScreen(pl);
128 else
129 delete pl;
130}
131
136{
137 ProgramInfo *pginfo = GetCurrentProgram();
138 if (!pginfo)
139 return;
140
141 QString startchannel = pginfo->GetChanNum();
142 uint startchanid = pginfo->GetChanID();
143 QDateTime starttime = pginfo->GetScheduledStartTime();
144 GuideGrid::RunProgramGuide(startchanid, startchannel, starttime);
145}
146
151{
152 ProgramInfo *pginfo = GetCurrentProgram();
153 if (!pginfo)
154 return;
155
156 if (pginfo->GetRecordingRuleID())
157 {
159 }
160 else
161 {
162 RecordingInfo ri(*pginfo);
163 ri.QuickRecord();
164 *pginfo = ri;
165 }
166}
167
172{
174}
175
180{
181 if (!pginfo)
182 return;
183
184 RecordingInfo ri(*pginfo);
185 EditScheduled(&ri);
186}
187
192{
194 auto *schededit = new ScheduleEditor(mainStack, recinfo);
195 if (schededit->Create())
196 {
197 mainStack->AddScreen(schededit);
198 }
199 else
200 {
201 delete schededit;
202 ShowOkPopup(tr("Recording rule does not exist."));
203 }
204}
205
210{
211 ProgramInfo *pginfo = GetCurrentProgram();
212 if (!pginfo)
213 return;
214
216 auto *ce = new CustomEdit(mainStack, pginfo);
217 if (ce->Create())
218 mainStack->AddScreen(ce);
219 else
220 delete ce;
221}
222
227{
228 if (!recinfo || !recinfo->GetRecordingRuleID())
229 return;
230
231 auto *recrule = new RecordingRule();
232
233 if (!recrule->LoadByProgram(recinfo))
234 LOG(VB_GENERAL, LOG_ERR, "Failed to load by program info");
235
236 if (!recrule->MakeOverride())
237 {
238 LOG(VB_GENERAL, LOG_ERR, "Failed to make Override");
239 delete recrule;
240 return;
241 }
242 recrule->m_type = kOverrideRecord;
243
245 auto *schededit = new ScheduleEditor(mainStack, recrule);
246 if (schededit->Create())
247 mainStack->AddScreen(schededit);
248 else
249 delete schededit;
250}
251
256{
257 ProgramInfo *pginfo = GetCurrentProgram();
258 if (!pginfo)
259 return;
260
261 ShowPrevious(pginfo->GetRecordingRuleID(), pginfo->GetTitle());
262}
263
267void ScheduleCommon::ShowPrevious(uint ruleid, const QString &title) const
268{
270 auto *pl = new PrevRecordedList(mainStack, ruleid, title);
271 if (pl->Create())
272 mainStack->AddScreen(pl);
273 else
274 delete pl;
275}
276
281void ScheduleCommon::EditRecording(bool may_watch_now)
282{
283 ProgramInfo *pginfo = GetCurrentProgram();
284 if (!pginfo)
285 return;
286
287 RecordingInfo recinfo(*pginfo);
288
289 QString timeFormat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
290
291 QString message = QString("%1 - %2 %3\n")
292 .arg(recinfo.GetRecordingStartTime().toLocalTime().toString(timeFormat),
293 recinfo.GetRecordingEndTime().toLocalTime().toString(timeFormat),
294 recinfo.toString(ProgramInfo::kTitleSubtitle, " - "));
295
296 message += "\n";
297 message += RecStatus::toDescription(recinfo.GetRecordingStatus(),
298 recinfo.GetRecordingRuleType(),
299 recinfo.GetRecordingStartTime());
300
301 QString messageConflict;
302 if (recinfo.GetRecordingStatus() == RecStatus::Conflict ||
304 {
305 std::vector<ProgramInfo *> *confList = RemoteGetConflictList(&recinfo);
306 uint chanid = recinfo.GetChanID();
307 uint sourceid = ChannelUtil::GetSourceIDForChannel(chanid);
308
309 for (auto *p : *confList)
310 {
311 if (sourceid == p->GetSourceID())
312 {
313 messageConflict += QString("%1 - %2 %3\n")
314 .arg(p->GetRecordingStartTime().toLocalTime().toString(timeFormat),
315 p->GetRecordingEndTime().toLocalTime().toString(timeFormat),
316 p->toString(ProgramInfo::kTitleSubtitle, " - "));
317 }
318 delete p;
319 }
320 delete confList;
321 }
322
323 if (!messageConflict.isEmpty())
324 {
325 message += " ";
326 message += tr("The following programs will be recorded instead:");
327 message += "\n";
328 message += messageConflict;
329 message += "\n";
330 }
331
332 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
333 auto *menuPopup = new MythDialogBox(message, popupStack, "recOptionPopup", true);
334
335 if (!menuPopup->Create())
336 {
337 delete menuPopup;
338 return;
339 }
340 menuPopup->SetReturnEvent(this, "editrecording");
341
342 QDateTime now = MythDate::current();
343
344 if(may_watch_now)
345 menuPopup->AddButton(tr("Watch This Channel"));
346
347 if (recinfo.GetRecordingStatus() == RecStatus::Unknown)
348 {
349 if (recinfo.GetRecordingEndTime() > now)
350 menuPopup->AddButtonV(tr("Record this showing"),
351 QVariant::fromValue(recinfo));
352 menuPopup->AddButtonV(tr("Record all showings"),
353 QVariant::fromValue(recinfo));
354 if (!recinfo.IsGeneric())
355 {
357 {
358 menuPopup->AddButtonV(tr("Record one showing"),
359 QVariant::fromValue(recinfo));
360 }
361 else
362 {
363 menuPopup->AddButtonV(tr("Record one showing (this episode)"),
364 QVariant::fromValue(recinfo));
365 }
366
367 }
368 menuPopup->AddButtonV(tr("Record all showings (this channel)"),
369 QVariant::fromValue(recinfo));
370 menuPopup->AddButtonV(tr("Edit recording rule"),
371 QVariant::fromValue(recinfo));
372 }
373 else if (recinfo.GetRecordingStatus() == RecStatus::Recording ||
377 {
378 if (recinfo.GetRecordingStatus() != RecStatus::Pending)
379 menuPopup->AddButtonV(tr("Stop this recording"),
380 QVariant::fromValue(recinfo));
381 menuPopup->AddButtonV(tr("Modify recording options"),
382 QVariant::fromValue(recinfo));
383 }
384 else
385 {
386 if (recinfo.GetRecordingStartTime() < now &&
387 recinfo.GetRecordingEndTime() > now &&
390 {
391 menuPopup->AddButtonV(tr("Restart this recording"),
392 QVariant::fromValue(recinfo));
393 }
394
395 if (recinfo.GetRecordingEndTime() > now &&
396 recinfo.GetRecordingRuleType() != kSingleRecord &&
407 {
408 menuPopup->AddButtonV(tr("Record this showing"),
409 QVariant::fromValue(recinfo));
410 if (recinfo.GetRecordingStartTime() > now &&
413 {
414 menuPopup->AddButtonV(tr("Forget previous recording"),
415 QVariant::fromValue(recinfo));
416 }
417 }
418
419 if (recinfo.GetRecordingRuleType() != kSingleRecord &&
420 recinfo.GetRecordingRuleType() != kDontRecord &&
428 {
429 if (recinfo.GetRecordingStatus() == RecStatus::WillRecord ||
431 menuPopup->AddButtonV(tr("Don't record this showing"),
432 QVariant::fromValue(recinfo));
433
434 const RecordingDupMethodType dupmethod =
435 recinfo.GetDuplicateCheckMethod();
436 static const QRegularExpression kGenericEpisodeRE { "0000$" };
437 if (recinfo.GetRecordingRuleType() != kOverrideRecord &&
438 ((recinfo.GetFindID() != 0 &&
439 IsFindApplicable(recinfo)) ||
441 !recinfo.GetProgramID().contains(kGenericEpisodeRE)) &&
442 ((((dupmethod & kDupCheckNone) == 0) &&
443 !recinfo.GetProgramID().isEmpty() &&
444 (recinfo.GetFindID() != 0 ||
445 !IsFindApplicable(recinfo))) ||
446 (((dupmethod & kDupCheckSub) != 0) &&
447 !recinfo.GetSubtitle().isEmpty()) ||
448 (((dupmethod & kDupCheckDesc) != 0) &&
449 !recinfo.GetDescription().isEmpty()) ||
450 (((dupmethod & kDupCheckSubThenDesc) != 0) &&
451 (!recinfo.GetSubtitle().isEmpty() ||
452 !recinfo.GetDescription().isEmpty())) ))
453 {
454 menuPopup->AddButtonV(tr("Never record this episode"),
455 QVariant::fromValue(recinfo));
456 }
457 }
458
459 if (recinfo.GetRecordingRuleType() == kOverrideRecord ||
461 {
462 menuPopup->AddButtonV(tr("Edit override rule"),
463 QVariant::fromValue(recinfo));
464 menuPopup->AddButtonV(tr("Delete override rule"),
465 QVariant::fromValue(recinfo));
466 }
467 else
468 {
469 if (recinfo.GetRecordingRuleType() != kSingleRecord &&
471 menuPopup->AddButtonV(tr("Add override rule"),
472 QVariant::fromValue(recinfo));
473 menuPopup->AddButtonV(tr("Edit recording rule"),
474 QVariant::fromValue(recinfo));
475 menuPopup->AddButtonV(tr("Delete recording rule"),
476 QVariant::fromValue(recinfo));
477 }
478 }
479
480 popupStack->AddScreen(menuPopup);
481}
482
484{
486}
487
489{
490 if (event->type() == DialogCompletionEvent::kEventType)
491 {
492 auto *dce = (DialogCompletionEvent*)event;
493
494 QString resultid = dce->GetId();
495 QString resulttext = dce->GetResultText();
496
497 if (resultid == "editrecording")
498 {
499 if (!dce->GetData().canConvert<RecordingInfo>())
500 return;
501
502 auto recInfo = dce->GetData().value<RecordingInfo>();
503
504 if (resulttext == tr("Record this showing"))
505 {
506 if (recInfo.GetRecordingRuleType() == kNotRecording)
507 {
509 }
510 else
511 {
512 recInfo.ApplyRecordStateChange(kOverrideRecord);
513 if (recInfo.GetRecordingStartTime() < MythDate::current())
514 recInfo.ReactivateRecording();
515 }
516 }
517 else if (resulttext == tr("Record all showings"))
518 {
519 recInfo.ApplyRecordStateChange(kAllRecord);
520 }
521 else if (resulttext == tr("Record one showing (this episode)") ||
522 resulttext == tr("Record one showing"))
523 {
524 recInfo.ApplyRecordStateChange(kOneRecord, false);
525 recInfo.GetRecordingRule()->m_filter |= 64; // This episode
526 recInfo.GetRecordingRule()->Save();
527 }
528 else if (resulttext == tr("Record all showings (this channel)"))
529 {
530 recInfo.ApplyRecordStateChange(kAllRecord, false);
531 recInfo.GetRecordingRule()->m_filter |= 1024; // This channel
532 recInfo.GetRecordingRule()->Save();
533 }
534 else if (resulttext == tr("Stop this recording"))
535 {
536 RemoteStopRecording(&recInfo);
537 }
538 else if (resulttext == tr("Modify recording options") ||
539 resulttext == tr("Add override rule"))
540 {
541 if (recInfo.GetRecordingRuleType() == kSingleRecord ||
542 recInfo.GetRecordingRuleType() == kOverrideRecord ||
543 recInfo.GetRecordingRuleType() == kOneRecord)
544 EditScheduled(&recInfo);
545 else
546 MakeOverride(&recInfo);
547 }
548 else if (resulttext == tr("Restart this recording"))
549 {
550 recInfo.ReactivateRecording();
551 }
552 else if (resulttext == tr("Forget previous recording"))
553 {
554 recInfo.ForgetHistory();
555 }
556 else if (resulttext == tr("Don't record this showing"))
557 {
558 recInfo.ApplyRecordStateChange(kDontRecord);
559 }
560 else if (resulttext == tr("Never record this episode"))
561 {
562 recInfo.ApplyNeverRecord();
563 }
564 else if (resulttext == tr("Edit recording rule") ||
565 resulttext == tr("Edit override rule"))
566 {
567 EditScheduled(&recInfo);
568 }
569 else if (resulttext == tr("Delete recording rule") ||
570 resulttext == tr("Delete override rule"))
571 {
572 recInfo.ApplyRecordStateChange(kNotRecording);
573 }
574 }
575 else if (resultid == "sortgroupmenu")
576 {
578 if (resulttext == tr("Group By Channel Number"))
579 groupBy = ProgGroupBy::ChanNum;
580 else if (resulttext == tr("Group By Call Sign"))
581 groupBy = ProgGroupBy::CallSign;
582 else if (resulttext == tr("Group By Program ID"))
583 groupBy = ProgGroupBy::ProgramId;
584 else if (resulttext == tr("Group By None"))
585 groupBy = ProgGroupBy::None;
586 gCoreContext->SaveSetting("ProgramListGroupBy", (int)groupBy);
587 MythEvent me("GROUPBY_CHANGE");
589 }
590 }
591}
592
598{
599 return recInfo.GetRecordingRuleType() == kDailyRecord ||
601}
602
604{
606 "ProgramListGroupBy", (int)ProgGroupBy::ChanNum);
607}
608
610{
611 sortGroupMenu->AddItem(tr("Group By Channel Number"));
612 sortGroupMenu->AddItem(tr("Group By Call Sign"));
613 sortGroupMenu->AddItem(tr("Group By Program ID"));
614 sortGroupMenu->AddItem(tr("Group By None"));
615}
static uint GetSourceIDForChannel(uint chanid)
A screen to create a fully custom recording.
Definition: customedit.h:18
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:40
static const Type kEventType
Definition: mythdialogbox.h:55
static void RunProgramGuide(uint startChanId, const QString &startChanNum, const QDateTime &startTime, TV *player=nullptr, bool embedVideo=false, bool allowFinder=true, int changrpid=-1)
Definition: guidegrid.cpp:410
void SaveSetting(const QString &key, int newValue)
QString GetSetting(const QString &key, const QString &defaultval="")
void dispatch(const MythEvent &event)
int GetNumSetting(const QString &key, int defaultval=0)
Basic menu dialog, message and a list of options.
This class is used as a container for messages.
Definition: mythevent.h:17
MythScreenStack * GetMainStack()
MythScreenStack * GetStack(const QString &Stackname)
void AddItem(const QString &title)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Holds information on recordings and videos.
Definition: programinfo.h:74
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:380
uint GetRecordingRuleID(void) const
Definition: programinfo.h:460
RecordingDupMethodType GetDuplicateCheckMethod(void) const
What should be compared to determine if two programs are the same?
Definition: programinfo.h:470
QString GetSeriesID(void) const
Definition: programinfo.h:446
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
QString GetProgramID(void) const
Definition: programinfo.h:447
QString GetDescription(void) const
Definition: programinfo.h:372
QString GetTitle(void) const
Definition: programinfo.h:368
bool IsGeneric(void) const
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:412
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:398
uint GetFindID(void) const
Definition: programinfo.h:479
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:384
CategoryType GetCategoryType(void) const
Definition: programinfo.h:449
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:458
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:420
QString GetSubtitle(void) const
Definition: programinfo.h:370
RecordingType GetRecordingRuleType(void) const
Definition: programinfo.h:462
static QString toDescription(Type recstatus, RecordingType rectype, const QDateTime &recstartts)
Converts "recstatus" into a long human readable description.
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:36
void ApplyRecordStateChange(RecordingType newstate, bool save=true)
Sets RecordingType of "record", creating "record" if it does not exist.
void QuickRecord(void)
Create a kSingleRecord if not already scheduled.
Internal representation of a recording rule, mirrors the record table.
Definition: recordingrule.h:30
virtual void EditScheduled(void)
Creates a dialog for editing the recording schedule.
virtual void EditRecording(bool may_watch_now=false)
Creates a dialog for editing the recording status, blocking until user leaves dialog.
static ProgGroupBy::Type GetProgramListGroupBy(void)
virtual ProgramInfo * GetCurrentProgram(void) const
virtual void ShowDetails(void) const
Show the Program Details screen.
virtual void AddGroupMenuItems(MythMenu *sortGroupMenu)
void customEvent(QEvent *event) override
virtual void EditCustom(void)
Creates a dialog for creating a custom recording rule.
virtual void ShowUpcomingScheduled(void) const
Show the upcoming recordings for this recording rule.
virtual void ShowGuide(void) const
Show the program guide.
virtual void QuickRecord(void)
Create a kSingleRecord or bring up recording dialog.
static bool IsFindApplicable(const RecordingInfo &recInfo)
Returns true if a search should be employed to find a matching program.
virtual void ShowUpcoming(void) const
Show the upcoming recordings for this title.
virtual void ShowChannelSearch(void) const
Show the channel search.
static void MakeOverride(RecordingInfo *recinfo)
Creates a dialog for editing an override recording schedule.
virtual void ShowPrevious(void) const
Show the previous recordings for this recording rule.
Construct a recording schedule.
unsigned int uint
Definition: compat.h:60
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
@ plChannel
Definition: proglist.h:28
@ plRecordid
Definition: proglist.h:30
@ plTitle
Definition: proglist.h:19
std::vector< ProgramInfo * > * RemoteGetConflictList(const ProgramInfo *pginfo)
@ kOneRecord
@ kWeeklyRecord
@ kNotRecording
@ kAllRecord
@ kOverrideRecord
@ kSingleRecord
@ kDailyRecord
@ kDontRecord
RecordingDupMethodType
@ kDupCheckSub
@ kDupCheckSubThenDesc
@ kDupCheckDesc
@ kDupCheckNone
bool RemoteStopRecording(uint inputid)