MythTV  master
schedulecommon.cpp
Go to the documentation of this file.
1 
2 #include "schedulecommon.h"
3 
4 // QT
5 #include <QCoreApplication>
6 
7 // libmyth
8 #include "mythcorecontext.h"
9 #include "programinfo.h"
10 #include "remoteutil.h"
11 
12 // libmythtv
13 #include "recordinginfo.h"
14 #include "tvremoteutil.h"
15 
16 // libmythui
17 #include "mythscreentype.h"
18 #include "mythdialogbox.h"
19 #include "mythmainwindow.h"
20 
21 // mythfrontend
22 #include "scheduleeditor.h"
23 
24 #include "proglist.h"
25 #include "prevreclist.h"
26 #include "customedit.h"
27 #include "guidegrid.h"
28 #include "progdetails.h"
29 
34 {
35  ProgramInfo *pginfo = GetCurrentProgram();
36  if (!pginfo)
37  return;
38 
40  auto *details_dialog = new ProgDetails(mainStack, pginfo);
41 
42  if (!details_dialog->Create())
43  {
44  delete details_dialog;
45  return;
46  }
47 
48  mainStack->AddScreen(details_dialog);
49 }
50 
54 void ScheduleCommon::ShowUpcoming(const QString &title,
55  const QString &seriesid)
56 {
57  if (title.isEmpty())
58  return;
59 
61  auto *pl = new ProgLister(mainStack, plTitle, title, seriesid);
62  if (pl->Create())
63  {
64  mainStack->AddScreen(pl);
65  }
66  else
67  delete pl;
68 }
69 
74 {
75  ProgramInfo *pginfo = GetCurrentProgram();
76  if (!pginfo)
77  return;
78 
79  if (pginfo->GetChanID() == 0 &&
80  pginfo->GetRecordingRuleID() > 0)
81  return ShowUpcomingScheduled();
82 
83  ShowUpcoming(pginfo->GetTitle(), pginfo->GetSeriesID());
84 }
85 
90 {
91  ProgramInfo *pginfo = GetCurrentProgram();
92  if (!pginfo)
93  return;
94 
95  RecordingInfo ri(*pginfo);
96 
97  uint id = ri.GetRecordingRuleID();
98  if (id == 0)
99  return ShowUpcoming(pginfo->GetTitle(), pginfo->GetSeriesID());
100 
102  auto *pl = new ProgLister(mainStack, plRecordid, QString::number(id), "");
103 
104  if (pl->Create())
105  mainStack->AddScreen(pl);
106  else
107  delete pl;
108 }
109 
114 {
115  ProgramInfo *pginfo = GetCurrentProgram();
116  if (!pginfo)
117  return;
118 
120  auto *pl = new ProgLister(mainStack, plChannel,
121  QString::number(pginfo->GetChanID()), "",
122  pginfo->GetScheduledStartTime());
123  if (pl->Create())
124  mainStack->AddScreen(pl);
125  else
126  delete pl;
127 }
128 
133 {
134  ProgramInfo *pginfo = GetCurrentProgram();
135  if (!pginfo)
136  return;
137 
138  QString startchannel = pginfo->GetChanNum();
139  uint startchanid = pginfo->GetChanID();
140  QDateTime starttime = pginfo->GetScheduledStartTime();
141  GuideGrid::RunProgramGuide(startchanid, startchannel, starttime);
142 }
143 
148 {
149  ProgramInfo *pginfo = GetCurrentProgram();
150  if (!pginfo)
151  return;
152 
153  if (pginfo->GetRecordingRuleID())
154  EditRecording();
155  else
156  {
157  RecordingInfo ri(*pginfo);
158  ri.QuickRecord();
159  *pginfo = ri;
160  }
161 }
162 
167 {
169 }
170 
175 {
176  if (!pginfo)
177  return;
178 
179  RecordingInfo ri(*pginfo);
180  EditScheduled(&ri);
181 }
182 
187 {
189  auto *schededit = new ScheduleEditor(mainStack, recinfo);
190  if (schededit->Create())
191  mainStack->AddScreen(schededit);
192  else
193  {
194  delete schededit;
195  ShowOkPopup(tr("Recording rule does not exist."));
196  }
197 }
198 
203 {
204  ProgramInfo *pginfo = GetCurrentProgram();
205  if (!pginfo)
206  return;
207 
209  auto *ce = new CustomEdit(mainStack, pginfo);
210  if (ce->Create())
211  mainStack->AddScreen(ce);
212  else
213  delete ce;
214 }
215 
220 {
221  if (!recinfo || !recinfo->GetRecordingRuleID())
222  return;
223 
224  auto *recrule = new RecordingRule();
225 
226  if (!recrule->LoadByProgram(static_cast<ProgramInfo*>(recinfo)))
227  LOG(VB_GENERAL, LOG_ERR, "Failed to load by program info");
228 
229  if (!recrule->MakeOverride())
230  {
231  LOG(VB_GENERAL, LOG_ERR, "Failed to make Override");
232  delete recrule;
233  return;
234  }
235  recrule->m_type = kOverrideRecord;
236 
238  auto *schededit = new ScheduleEditor(mainStack, recrule);
239  if (schededit->Create())
240  mainStack->AddScreen(schededit);
241  else
242  delete schededit;
243 }
244 
249 {
250  ProgramInfo *pginfo = GetCurrentProgram();
251  if (!pginfo)
252  return;
253 
254  ShowPrevious(pginfo->GetRecordingRuleID(), pginfo->GetTitle());
255 }
256 
260 void ScheduleCommon::ShowPrevious(uint ruleid, const QString &title) const
261 {
263  auto *pl = new PrevRecordedList(mainStack, ruleid, title);
264  if (pl->Create())
265  mainStack->AddScreen(pl);
266  else
267  delete pl;
268 }
269 
274 void ScheduleCommon::EditRecording(bool may_watch_now)
275 {
276  ProgramInfo *pginfo = GetCurrentProgram();
277  if (!pginfo)
278  return;
279 
280  RecordingInfo recinfo(*pginfo);
281 
282  QString timeFormat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
283 
284  QString message = recinfo.toString(ProgramInfo::kTitleSubtitle, " - ");
285 
286  message += "\n\n";
287  message += RecStatus::toDescription(recinfo.GetRecordingStatus(),
288  recinfo.GetRecordingRuleType(),
289  recinfo.GetRecordingStartTime());
290 
291  if (recinfo.GetRecordingStatus() == RecStatus::Conflict ||
293  {
294  vector<ProgramInfo *> *confList = RemoteGetConflictList(&recinfo);
295 
296  if (!confList->empty())
297  {
298  message += " ";
299  message += tr("The following programs will be recorded instead:");
300  message += "\n";
301  }
302 
303  uint maxi = 0;
304  for (; confList->begin() != confList->end() && maxi < 4; maxi++)
305  {
306  ProgramInfo *p = *confList->begin();
307  message += QString("%1 - %2 %3\n")
308  .arg(p->GetRecordingStartTime()
309  .toLocalTime().toString(timeFormat))
310  .arg(p->GetRecordingEndTime()
311  .toLocalTime().toString(timeFormat))
312  .arg(p->toString(ProgramInfo::kTitleSubtitle, " - "));
313  delete p;
314  confList->erase(confList->begin());
315  }
316  message += "\n";
317  while (!confList->empty())
318  {
319  delete confList->back();
320  confList->pop_back();
321  }
322  delete confList;
323  }
324 
325  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
326  auto *menuPopup = new MythDialogBox(message, popupStack,
327  "recOptionPopup", true);
328  if (!menuPopup->Create())
329  {
330  delete menuPopup;
331  return;
332  }
333  menuPopup->SetReturnEvent(this, "editrecording");
334 
335  QDateTime now = MythDate::current();
336 
337  if(may_watch_now)
338  menuPopup->AddButton(tr("Watch This Channel"));
339 
340  if (recinfo.GetRecordingStatus() == RecStatus::Unknown)
341  {
342  if (recinfo.GetRecordingEndTime() > now)
343  menuPopup->AddButton(tr("Record this showing"),
344  QVariant::fromValue(recinfo));
345  menuPopup->AddButton(tr("Record all showings"),
346  QVariant::fromValue(recinfo));
347  if (!recinfo.IsGeneric())
348  {
350  {
351  menuPopup->AddButton(tr("Record one showing"),
352  QVariant::fromValue(recinfo));
353  }
354  else
355  {
356  menuPopup->AddButton(tr("Record one showing (this episode)"),
357  QVariant::fromValue(recinfo));
358  }
359 
360  }
361  menuPopup->AddButton(tr("Record all showings (this channel)"),
362  QVariant::fromValue(recinfo));
363  menuPopup->AddButton(tr("Edit recording rule"),
364  QVariant::fromValue(recinfo));
365  }
366  else if (recinfo.GetRecordingStatus() == RecStatus::Recording ||
367  recinfo.GetRecordingStatus() == RecStatus::Tuning ||
368  recinfo.GetRecordingStatus() == RecStatus::Failing ||
370  {
371  if (recinfo.GetRecordingStatus() != RecStatus::Pending)
372  menuPopup->AddButton(tr("Stop this recording"),
373  QVariant::fromValue(recinfo));
374  menuPopup->AddButton(tr("Modify recording options"),
375  QVariant::fromValue(recinfo));
376  }
377  else
378  {
379  if (recinfo.GetRecordingStartTime() < now &&
380  recinfo.GetRecordingEndTime() > now &&
383  {
384  menuPopup->AddButton(tr("Restart this recording"),
385  QVariant::fromValue(recinfo));
386  }
387 
388  if (recinfo.GetRecordingEndTime() > now &&
389  recinfo.GetRecordingRuleType() != kSingleRecord &&
390  recinfo.GetRecordingRuleType() != kOverrideRecord &&
397  recinfo.GetRecordingStatus() == RecStatus::Repeat ||
400  {
401  menuPopup->AddButton(tr("Record this showing"),
402  QVariant::fromValue(recinfo));
403  if (recinfo.GetRecordingStartTime() > now &&
406  {
407  menuPopup->AddButton(tr("Forget previous recording"),
408  QVariant::fromValue(recinfo));
409  }
410  }
411 
412  if (recinfo.GetRecordingRuleType() != kSingleRecord &&
413  recinfo.GetRecordingRuleType() != kDontRecord &&
421  {
422  if (recinfo.GetRecordingStatus() == RecStatus::WillRecord ||
424  menuPopup->AddButton(tr("Don't record this showing"),
425  QVariant::fromValue(recinfo));
426 
427  const RecordingDupMethodType dupmethod =
428  recinfo.GetDuplicateCheckMethod();
429  if (recinfo.GetRecordingRuleType() != kOverrideRecord &&
430  !((recinfo.GetFindID() == 0 ||
431  !IsFindApplicable(recinfo)) &&
433  recinfo.GetProgramID().contains(QRegExp("0000$"))) &&
434  ((((dupmethod & kDupCheckNone) == 0) &&
435  !recinfo.GetProgramID().isEmpty() &&
436  (recinfo.GetFindID() != 0 ||
437  !IsFindApplicable(recinfo))) ||
438  (((dupmethod & kDupCheckSub) != 0) &&
439  !recinfo.GetSubtitle().isEmpty()) ||
440  (((dupmethod & kDupCheckDesc) != 0) &&
441  !recinfo.GetDescription().isEmpty()) ||
442  (((dupmethod & kDupCheckSubThenDesc) != 0) &&
443  (!recinfo.GetSubtitle().isEmpty() ||
444  !recinfo.GetDescription().isEmpty())) ))
445  {
446  menuPopup->AddButton(tr("Never record this episode"),
447  QVariant::fromValue(recinfo));
448  }
449  }
450 
451  if (recinfo.GetRecordingRuleType() == kOverrideRecord ||
452  recinfo.GetRecordingRuleType() == kDontRecord)
453  {
454  menuPopup->AddButton(tr("Edit override rule"),
455  QVariant::fromValue(recinfo));
456  menuPopup->AddButton(tr("Delete override rule"),
457  QVariant::fromValue(recinfo));
458  }
459  else
460  {
461  if (recinfo.GetRecordingRuleType() != kSingleRecord &&
463  menuPopup->AddButton(tr("Add override rule"),
464  QVariant::fromValue(recinfo));
465  menuPopup->AddButton(tr("Edit recording rule"),
466  QVariant::fromValue(recinfo));
467  menuPopup->AddButton(tr("Delete recording rule"),
468  QVariant::fromValue(recinfo));
469  }
470  }
471 
472  popupStack->AddScreen(menuPopup);
473 }
474 
475 void ScheduleCommon::customEvent(QEvent *event)
476 {
477  if (event->type() == DialogCompletionEvent::kEventType)
478  {
479  auto *dce = (DialogCompletionEvent*)(event);
480 
481  QString resultid = dce->GetId();
482  QString resulttext = dce->GetResultText();
483 
484  if (resultid == "editrecording")
485  {
486  if (!dce->GetData().canConvert<RecordingInfo>())
487  return;
488 
489  RecordingInfo recInfo = dce->GetData().value<RecordingInfo>();
490 
491  if (resulttext == tr("Record this showing"))
492  {
493  if (recInfo.GetRecordingRuleType() == kNotRecording)
495  else
496  {
498  if (recInfo.GetRecordingStartTime() < MythDate::current())
499  recInfo.ReactivateRecording();
500  }
501  }
502  else if (resulttext == tr("Record all showings"))
504  else if (resulttext == tr("Record one showing (this episode)") ||
505  resulttext == tr("Record one showing"))
506  {
507  recInfo.ApplyRecordStateChange(kOneRecord, false);
508  recInfo.GetRecordingRule()->m_filter |= 64; // This episode
509  recInfo.GetRecordingRule()->Save();
510  }
511  else if (resulttext == tr("Record all showings (this channel)"))
512  {
513  recInfo.ApplyRecordStateChange(kAllRecord, false);
514  recInfo.GetRecordingRule()->m_filter |= 1024; // This channel
515  recInfo.GetRecordingRule()->Save();
516  }
517  else if (resulttext == tr("Stop this recording"))
518  {
519  RemoteStopRecording(&recInfo);
520  }
521  else if (resulttext == tr("Modify recording options") ||
522  resulttext == tr("Add override rule"))
523  {
524  if (recInfo.GetRecordingRuleType() == kSingleRecord ||
525  recInfo.GetRecordingRuleType() == kOverrideRecord ||
526  recInfo.GetRecordingRuleType() == kOneRecord)
527  EditScheduled(&recInfo);
528  else
529  MakeOverride(&recInfo);
530  }
531  else if (resulttext == tr("Restart this recording"))
532  recInfo.ReactivateRecording();
533  else if (resulttext == tr("Forget previous recording"))
534  recInfo.ForgetHistory();
535  else if (resulttext == tr("Don't record this showing"))
537  else if (resulttext == tr("Never record this episode"))
538  {
539  recInfo.ApplyNeverRecord();
540  }
541  else if (resulttext == tr("Edit recording rule") ||
542  resulttext == tr("Edit override rule"))
543  EditScheduled(&recInfo);
544  else if (resulttext == tr("Delete recording rule") ||
545  resulttext == tr("Delete override rule"))
547  }
548  }
549 }
550 
556 {
557  return recInfo.GetRecordingRuleType() == kDailyRecord ||
558  recInfo.GetRecordingRuleType() == kWeeklyRecord;
559 }
560 
void ReactivateRecording(void)
Asks the scheduler to restart this recording if possible.
RecordingDupMethodType GetDuplicateCheckMethod(void) const
What should be compared to determine if two programs are the same?
Definition: programinfo.h:453
virtual void ShowUpcomingScheduled(void) const
Show the upcoming recordings for this recording rule.
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
virtual void ShowUpcoming(void) const
Show the upcoming recordings for this title.
A screen to create a fully custom recording.
Definition: customedit.h:17
Basic menu dialog, message and a list of options.
RecordingRule * GetRecordingRule(void)
Returns the "record" field, creating it if necessary.
QString GetTitle(void) const
Definition: programinfo.h:355
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:34
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
MythScreenStack * GetStack(const QString &stackname)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythScreenStack * GetMainStack()
virtual void ShowDetails(void) const
Show the Program Details screen.
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:370
static Type kEventType
Definition: mythdialogbox.h:56
RecordingDupMethodType
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:384
bool Save(bool sendSig=true)
Holds information on recordings and videos.
Definition: programinfo.h:67
void ApplyRecordStateChange(RecordingType newstate, bool save=true)
Sets RecordingType of "record", creating "record" if it does not exist.
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
virtual void ShowGuide(void) const
Show the program guide.
virtual void ShowPrevious(void) const
Show the previous recordings for this recording rule.
void ForgetHistory(void)
Forget the recording of a program so it will be recorded again.
QString GetDescription(void) const
Definition: programinfo.h:359
Construct a recording schedule.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QString GetSetting(const QString &key, const QString &defaultval="")
static QString toDescription(Type recstatus, RecordingType rectype, const QDateTime &recstartts)
Converts "recstatus" into a long human readable description.
Definition: recStatus.cpp:187
QString GetSubtitle(void) const
Definition: programinfo.h:357
bool IsGeneric(void) const
unsigned int uint
Definition: compat.h:140
Internal representation of a recording rule, mirrors the record table.
Definition: recordingrule.h:32
void customEvent(QEvent *event) override
virtual void EditCustom(void)
Creates a dialog for creating a custom recording rule.
void QuickRecord(void)
Create a kSingleRecord if not already scheduled.
MythMainWindow * GetMythMainWindow(void)
virtual void ShowChannelSearch(void) const
Show the channel search.
QString GetSeriesID(void) const
Definition: programinfo.h:429
bool RemoteStopRecording(uint inputid)
vector< ProgramInfo * > * RemoteGetConflictList(const ProgramInfo *pginfo)
Definition: remoteutil.cpp:202
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:441
virtual void QuickRecord(void)
Create a kSingleRecord or bring up recording dialog.
virtual void EditScheduled(void)
Creates a dialog for editing the recording schedule.
RecordingType GetRecordingRuleType(void) const
Definition: programinfo.h:445
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:415
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:366
void ApplyNeverRecord(void)
Set this program to never be recorded by inserting 'history' for it into the database with a status o...
uint GetRecordingRuleID(void) const
Definition: programinfo.h:443
QString GetProgramID(void) const
Definition: programinfo.h:430
static bool IsFindApplicable(const RecordingInfo &recInfo)
Returns true if a search should be employed to find a matching program.
uint GetFindID(void) const
Definition: programinfo.h:464
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:398
unsigned m_filter
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:406
static void MakeOverride(RecordingInfo *recinfo)
Creates a dialog for editing an override recording schedule.
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
CategoryType GetCategoryType(void) const
Definition: programinfo.h:432
virtual ProgramInfo * GetCurrentProgram(void) const
virtual void EditRecording(bool may_watch_now=false)
Creates a dialog for editing the recording status, blocking until user leaves dialog.