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())
158 else
159 {
160 RecordingInfo ri(*pginfo);
161 ri.QuickRecord();
162 *pginfo = ri;
163 }
164}
165
170{
172}
173
178{
179 if (!pginfo)
180 return;
181
182 RecordingInfo ri(*pginfo);
183 EditScheduled(&ri);
184}
185
190{
192 auto *schededit = new ScheduleEditor(mainStack, recinfo);
193 if (schededit->Create())
194 mainStack->AddScreen(schededit);
195 else
196 {
197 delete schededit;
198 ShowOkPopup(tr("Recording rule does not exist."));
199 }
200}
201
206{
207 ProgramInfo *pginfo = GetCurrentProgram();
208 if (!pginfo)
209 return;
210
212 auto *ce = new CustomEdit(mainStack, pginfo);
213 if (ce->Create())
214 mainStack->AddScreen(ce);
215 else
216 delete ce;
217}
218
223{
224 if (!recinfo || !recinfo->GetRecordingRuleID())
225 return;
226
227 auto *recrule = new RecordingRule();
228
229 if (!recrule->LoadByProgram(recinfo))
230 LOG(VB_GENERAL, LOG_ERR, "Failed to load by program info");
231
232 if (!recrule->MakeOverride())
233 {
234 LOG(VB_GENERAL, LOG_ERR, "Failed to make Override");
235 delete recrule;
236 return;
237 }
238 recrule->m_type = kOverrideRecord;
239
241 auto *schededit = new ScheduleEditor(mainStack, recrule);
242 if (schededit->Create())
243 mainStack->AddScreen(schededit);
244 else
245 delete schededit;
246}
247
252{
253 ProgramInfo *pginfo = GetCurrentProgram();
254 if (!pginfo)
255 return;
256
257 ShowPrevious(pginfo->GetRecordingRuleID(), pginfo->GetTitle());
258}
259
263void ScheduleCommon::ShowPrevious(uint ruleid, const QString &title) const
264{
266 auto *pl = new PrevRecordedList(mainStack, ruleid, title);
267 if (pl->Create())
268 mainStack->AddScreen(pl);
269 else
270 delete pl;
271}
272
277void ScheduleCommon::EditRecording(bool may_watch_now)
278{
279 ProgramInfo *pginfo = GetCurrentProgram();
280 if (!pginfo)
281 return;
282
283 RecordingInfo recinfo(*pginfo);
284
285 QString timeFormat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
286
287 QString message = QString("%1 - %2 %3\n")
288 .arg(recinfo.GetRecordingStartTime().toLocalTime().toString(timeFormat),
289 recinfo.GetRecordingEndTime().toLocalTime().toString(timeFormat),
290 recinfo.toString(ProgramInfo::kTitleSubtitle, " - "));
291
292 message += "\n";
293 message += RecStatus::toDescription(recinfo.GetRecordingStatus(),
294 recinfo.GetRecordingRuleType(),
295 recinfo.GetRecordingStartTime());
296
297 QString messageConflict;
298 if (recinfo.GetRecordingStatus() == RecStatus::Conflict ||
300 {
301 std::vector<ProgramInfo *> *confList = RemoteGetConflictList(&recinfo);
302 uint chanid = recinfo.GetChanID();
303 uint sourceid = ChannelUtil::GetSourceIDForChannel(chanid);
304
305 for (auto *p : *confList)
306 {
307 if (sourceid == p->GetSourceID())
308 {
309 messageConflict += QString("%1 - %2 %3\n")
310 .arg(p->GetRecordingStartTime().toLocalTime().toString(timeFormat),
311 p->GetRecordingEndTime().toLocalTime().toString(timeFormat),
312 p->toString(ProgramInfo::kTitleSubtitle, " - "));
313 }
314 delete p;
315 }
316 delete confList;
317 }
318
319 if (!messageConflict.isEmpty())
320 {
321 message += " ";
322 message += tr("The following programs will be recorded instead:");
323 message += "\n";
324 message += messageConflict;
325 message += "\n";
326 }
327
328 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
329 auto *menuPopup = new MythDialogBox(message, popupStack, "recOptionPopup", true);
330
331 if (!menuPopup->Create())
332 {
333 delete menuPopup;
334 return;
335 }
336 menuPopup->SetReturnEvent(this, "editrecording");
337
338 QDateTime now = MythDate::current();
339
340 if(may_watch_now)
341 menuPopup->AddButton(tr("Watch This Channel"));
342
343 if (recinfo.GetRecordingStatus() == RecStatus::Unknown)
344 {
345 if (recinfo.GetRecordingEndTime() > now)
346 menuPopup->AddButtonV(tr("Record this showing"),
347 QVariant::fromValue(recinfo));
348 menuPopup->AddButtonV(tr("Record all showings"),
349 QVariant::fromValue(recinfo));
350 if (!recinfo.IsGeneric())
351 {
353 {
354 menuPopup->AddButtonV(tr("Record one showing"),
355 QVariant::fromValue(recinfo));
356 }
357 else
358 {
359 menuPopup->AddButtonV(tr("Record one showing (this episode)"),
360 QVariant::fromValue(recinfo));
361 }
362
363 }
364 menuPopup->AddButtonV(tr("Record all showings (this channel)"),
365 QVariant::fromValue(recinfo));
366 menuPopup->AddButtonV(tr("Edit recording rule"),
367 QVariant::fromValue(recinfo));
368 }
369 else if (recinfo.GetRecordingStatus() == RecStatus::Recording ||
373 {
374 if (recinfo.GetRecordingStatus() != RecStatus::Pending)
375 menuPopup->AddButtonV(tr("Stop this recording"),
376 QVariant::fromValue(recinfo));
377 menuPopup->AddButtonV(tr("Modify recording options"),
378 QVariant::fromValue(recinfo));
379 }
380 else
381 {
382 if (recinfo.GetRecordingStartTime() < now &&
383 recinfo.GetRecordingEndTime() > now &&
386 {
387 menuPopup->AddButtonV(tr("Restart this recording"),
388 QVariant::fromValue(recinfo));
389 }
390
391 if (recinfo.GetRecordingEndTime() > now &&
392 recinfo.GetRecordingRuleType() != kSingleRecord &&
403 {
404 menuPopup->AddButtonV(tr("Record this showing"),
405 QVariant::fromValue(recinfo));
406 if (recinfo.GetRecordingStartTime() > now &&
409 {
410 menuPopup->AddButtonV(tr("Forget previous recording"),
411 QVariant::fromValue(recinfo));
412 }
413 }
414
415 if (recinfo.GetRecordingRuleType() != kSingleRecord &&
416 recinfo.GetRecordingRuleType() != kDontRecord &&
424 {
425 if (recinfo.GetRecordingStatus() == RecStatus::WillRecord ||
427 menuPopup->AddButtonV(tr("Don't record this showing"),
428 QVariant::fromValue(recinfo));
429
430 const RecordingDupMethodType dupmethod =
431 recinfo.GetDuplicateCheckMethod();
432 static const QRegularExpression kGenericEpisodeRE { "0000$" };
433 if (recinfo.GetRecordingRuleType() != kOverrideRecord &&
434 ((recinfo.GetFindID() != 0 &&
435 IsFindApplicable(recinfo)) ||
437 !recinfo.GetProgramID().contains(kGenericEpisodeRE)) &&
438 ((((dupmethod & kDupCheckNone) == 0) &&
439 !recinfo.GetProgramID().isEmpty() &&
440 (recinfo.GetFindID() != 0 ||
441 !IsFindApplicable(recinfo))) ||
442 (((dupmethod & kDupCheckSub) != 0) &&
443 !recinfo.GetSubtitle().isEmpty()) ||
444 (((dupmethod & kDupCheckDesc) != 0) &&
445 !recinfo.GetDescription().isEmpty()) ||
446 (((dupmethod & kDupCheckSubThenDesc) != 0) &&
447 (!recinfo.GetSubtitle().isEmpty() ||
448 !recinfo.GetDescription().isEmpty())) ))
449 {
450 menuPopup->AddButtonV(tr("Never record this episode"),
451 QVariant::fromValue(recinfo));
452 }
453 }
454
455 if (recinfo.GetRecordingRuleType() == kOverrideRecord ||
457 {
458 menuPopup->AddButtonV(tr("Edit override rule"),
459 QVariant::fromValue(recinfo));
460 menuPopup->AddButtonV(tr("Delete override rule"),
461 QVariant::fromValue(recinfo));
462 }
463 else
464 {
465 if (recinfo.GetRecordingRuleType() != kSingleRecord &&
467 menuPopup->AddButtonV(tr("Add override rule"),
468 QVariant::fromValue(recinfo));
469 menuPopup->AddButtonV(tr("Edit recording rule"),
470 QVariant::fromValue(recinfo));
471 menuPopup->AddButtonV(tr("Delete recording rule"),
472 QVariant::fromValue(recinfo));
473 }
474 }
475
476 popupStack->AddScreen(menuPopup);
477}
478
480{
482}
483
485{
486 if (event->type() == DialogCompletionEvent::kEventType)
487 {
488 auto *dce = (DialogCompletionEvent*)(event);
489
490 QString resultid = dce->GetId();
491 QString resulttext = dce->GetResultText();
492
493 if (resultid == "editrecording")
494 {
495 if (!dce->GetData().canConvert<RecordingInfo>())
496 return;
497
498 auto recInfo = dce->GetData().value<RecordingInfo>();
499
500 if (resulttext == tr("Record this showing"))
501 {
502 if (recInfo.GetRecordingRuleType() == kNotRecording)
504 else
505 {
506 recInfo.ApplyRecordStateChange(kOverrideRecord);
507 if (recInfo.GetRecordingStartTime() < MythDate::current())
508 recInfo.ReactivateRecording();
509 }
510 }
511 else if (resulttext == tr("Record all showings"))
512 {
513 recInfo.ApplyRecordStateChange(kAllRecord);
514 }
515 else if (resulttext == tr("Record one showing (this episode)") ||
516 resulttext == tr("Record one showing"))
517 {
518 recInfo.ApplyRecordStateChange(kOneRecord, false);
519 recInfo.GetRecordingRule()->m_filter |= 64; // This episode
520 recInfo.GetRecordingRule()->Save();
521 }
522 else if (resulttext == tr("Record all showings (this channel)"))
523 {
524 recInfo.ApplyRecordStateChange(kAllRecord, false);
525 recInfo.GetRecordingRule()->m_filter |= 1024; // This channel
526 recInfo.GetRecordingRule()->Save();
527 }
528 else if (resulttext == tr("Stop this recording"))
529 {
530 RemoteStopRecording(&recInfo);
531 }
532 else if (resulttext == tr("Modify recording options") ||
533 resulttext == tr("Add override rule"))
534 {
535 if (recInfo.GetRecordingRuleType() == kSingleRecord ||
536 recInfo.GetRecordingRuleType() == kOverrideRecord ||
537 recInfo.GetRecordingRuleType() == kOneRecord)
538 EditScheduled(&recInfo);
539 else
540 MakeOverride(&recInfo);
541 }
542 else if (resulttext == tr("Restart this recording"))
543 {
544 recInfo.ReactivateRecording();
545 }
546 else if (resulttext == tr("Forget previous recording"))
547 {
548 recInfo.ForgetHistory();
549 }
550 else if (resulttext == tr("Don't record this showing"))
551 {
552 recInfo.ApplyRecordStateChange(kDontRecord);
553 }
554 else if (resulttext == tr("Never record this episode"))
555 {
556 recInfo.ApplyNeverRecord();
557 }
558 else if (resulttext == tr("Edit recording rule") ||
559 resulttext == tr("Edit override rule"))
560 {
561 EditScheduled(&recInfo);
562 }
563 else if (resulttext == tr("Delete recording rule") ||
564 resulttext == tr("Delete override rule"))
565 {
566 recInfo.ApplyRecordStateChange(kNotRecording);
567 }
568 }
569 else if (resultid == "sortgroupmenu")
570 {
572 if (resulttext == tr("Group By Channel Number"))
573 groupBy = ProgGroupBy::ChanNum;
574 else if (resulttext == tr("Group By Call Sign"))
575 groupBy = ProgGroupBy::CallSign;
576 else if (resulttext == tr("Group By Program ID"))
577 groupBy = ProgGroupBy::ProgramId;
578 else if (resulttext == tr("Group By None"))
579 groupBy = ProgGroupBy::None;
580 gCoreContext->SaveSetting("ProgramListGroupBy", (int)groupBy);
581 MythEvent me("GROUPBY_CHANGE");
583 }
584 }
585}
586
592{
593 return recInfo.GetRecordingRuleType() == kDailyRecord ||
595}
596
598{
600 "ProgramListGroupBy", (int)ProgGroupBy::ChanNum);
601}
602
604{
605 sortGroupMenu->AddItem(tr("Group By Channel Number"));
606 sortGroupMenu->AddItem(tr("Group By Call Sign"));
607 sortGroupMenu->AddItem(tr("Group By Program ID"));
608 sortGroupMenu->AddItem(tr("Group By None"));
609}
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:41
static const Type kEventType
Definition: mythdialogbox.h:56
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:70
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:375
uint GetRecordingRuleID(void) const
Definition: programinfo.h:455
RecordingDupMethodType GetDuplicateCheckMethod(void) const
What should be compared to determine if two programs are the same?
Definition: programinfo.h:465
QString GetSeriesID(void) const
Definition: programinfo.h:441
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
QString GetProgramID(void) const
Definition: programinfo.h:442
QString GetDescription(void) const
Definition: programinfo.h:368
QString GetTitle(void) const
Definition: programinfo.h:364
bool IsGeneric(void) const
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:407
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:393
uint GetFindID(void) const
Definition: programinfo.h:474
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:379
CategoryType GetCategoryType(void) const
Definition: programinfo.h:444
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:453
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:415
QString GetSubtitle(void) const
Definition: programinfo.h:366
RecordingType GetRecordingRuleType(void) const
Definition: programinfo.h:457
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:68
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)