MythTV  master
scheduleeditor.cpp
Go to the documentation of this file.
1 
2 #include "scheduleeditor.h"
3 
4 // QT
5 #include <QCoreApplication>
6 #include <QHash>
7 #include <QString>
8 #include <utility>
9 
10 // Libmyth
11 #include "mythcorecontext.h"
12 #include "storagegroup.h"
13 #include "programtypes.h"
14 #include "recordingtypes.h"
15 
16 // Libmythtv
17 #include "playgroup.h"
18 #include "tv_play.h"
19 #include "recordingprofile.h"
20 #include "cardutil.h"
21 
22 // Libmythui
23 #include "mythmainwindow.h"
24 #include "mythuihelper.h"
25 #include "mythuibuttonlist.h"
26 #include "mythuibutton.h"
27 #include "mythuitext.h"
28 #include "mythuiimage.h"
29 #include "mythuistatetype.h"
30 #include "mythuispinbox.h"
31 #include "mythuicheckbox.h"
32 #include "mythdialogbox.h"
33 #include "mythprogressdialog.h"
34 #include "mythuifilebrowser.h"
35 #include "mythuimetadataresults.h"
36 #include "mythuiimageresults.h"
37 #include "videoutils.h"
38 #include "mythuiutils.h"
39 #include "mythtypes.h"
40 
41 #include "metadataimagehelper.h"
42 
43 // Mythfrontend
44 #include "proglist.h"
45 #include "viewschedulediff.h"
46 
47 #define ENUM_TO_QVARIANT(a) qVariantFromValue(static_cast<int>(a))
48 
49 //static const QString _Location = QObject::tr("Schedule Editor");
50 
51 // Define the strings inserted into the recordfilter table in the
52 // database. This should make them available to the translators.
53 static QString fs0(QT_TRANSLATE_NOOP("SchedFilterEditor", "New episode"));
54 static QString fs1(QT_TRANSLATE_NOOP("SchedFilterEditor", "Identifiable episode"));
55 static QString fs2(QT_TRANSLATE_NOOP("SchedFilterEditor", "First showing"));
56 static QString fs3(QT_TRANSLATE_NOOP("SchedFilterEditor", "Prime time"));
57 static QString fs4(QT_TRANSLATE_NOOP("SchedFilterEditor", "Commercial free"));
58 static QString fs5(QT_TRANSLATE_NOOP("SchedFilterEditor", "High definition"));
59 static QString fs6(QT_TRANSLATE_NOOP("SchedFilterEditor", "This episode"));
60 static QString fs7(QT_TRANSLATE_NOOP("SchedFilterEditor", "This series"));
61 static QString fs8(QT_TRANSLATE_NOOP("SchedFilterEditor", "This time"));
62 static QString fs9(QT_TRANSLATE_NOOP("SchedFilterEditor", "This day and time"));
63 static QString fs10(QT_TRANSLATE_NOOP("SchedFilterEditor", "This channel"));
64 static QString fs11(QT_TRANSLATE_NOOP("SchedFilterEditor", "No episodes"));
65 
66 void *ScheduleEditor::RunScheduleEditor(ProgramInfo *proginfo, void *player)
67 {
68  auto *rule = new RecordingRule();
69  rule->LoadByProgram(proginfo);
70 
72  auto *se = new ScheduleEditor(mainStack, rule, static_cast<TV*>(player));
73 
74  if (se->Create())
75  mainStack->AddScreen(se, (player == nullptr));
76  else
77  delete se;
78 
79  return nullptr;
80 }
81 
88  RecordingInfo *recInfo, TV *player)
89  : ScheduleCommon(parent, "ScheduleEditor"),
90  SchedOptMixin(*this, nullptr), FilterOptMixin(*this, nullptr),
91  StoreOptMixin(*this, nullptr), PostProcMixin(*this, nullptr),
92  m_recInfo(new RecordingInfo(*recInfo)),
93  m_player(player)
94 {
101 }
102 
104  RecordingRule *recRule, TV *player)
105  : ScheduleCommon(parent, "ScheduleEditor"),
106  SchedOptMixin(*this, recRule),
107  FilterOptMixin(*this, recRule),
108  StoreOptMixin(*this, recRule),
109  PostProcMixin(*this, recRule),
110  m_recordingRule(recRule),
111  m_player(player), m_view(kMainView)
112 {
113 }
114 
116 {
117  delete m_recordingRule;
118 
119  // if we have a player, we need to tell we are done
120  if (m_player)
121  {
122  QString message = QString("VIEWSCHEDULED_EXITING");
123  qApp->postEvent(m_player, new MythEvent(message));
124  }
125 }
126 
128 {
129  if (!LoadWindowFromXML("schedule-ui.xml", "scheduleeditor", this))
130  return false;
131 
132  bool err = false;
133 
134  UIUtilE::Assign(this, m_rulesList, "rules", &err);
135 
136  UIUtilW::Assign(this, m_schedOptButton, "schedoptions");
137  UIUtilW::Assign(this, m_storeOptButton, "storeoptions");
138  UIUtilW::Assign(this, m_postProcButton, "postprocessing");
139  UIUtilW::Assign(this, m_metadataButton, "metadata");
140  UIUtilW::Assign(this, m_schedInfoButton, "schedinfo");
141  UIUtilW::Assign(this, m_previewButton, "preview");
142  UIUtilW::Assign(this, m_filtersButton, "filters");
143 
144  SchedOptMixin::Create(&err);
146  StoreOptMixin::Create(&err);
147  PostProcMixin::Create(&err);
148 
149  UIUtilW::Assign(this, m_cancelButton, "cancel");
150  UIUtilE::Assign(this, m_saveButton, "save", &err);
151 
152  if (err)
153  {
154  LOG(VB_GENERAL, LOG_ERR, "ScheduleEditor, theme is missing "
155  "required elements");
156  return false;
157  }
158 
159  connect(m_rulesList, SIGNAL(itemSelected(MythUIButtonListItem *)),
161 
162  if (m_schedOptButton)
163  connect(m_schedOptButton, SIGNAL(Clicked()), SLOT(ShowSchedOpt()));
164  if (m_filtersButton)
165  connect(m_filtersButton, SIGNAL(Clicked()), SLOT(ShowFilters()));
166  if (m_storeOptButton)
167  connect(m_storeOptButton, SIGNAL(Clicked()), SLOT(ShowStoreOpt()));
168  if (m_postProcButton)
169  connect(m_postProcButton, SIGNAL(Clicked()), SLOT(ShowPostProc()));
170  if (m_schedInfoButton)
171  connect(m_schedInfoButton, SIGNAL(Clicked()), SLOT(ShowSchedInfo()));
172  if (m_previewButton)
173  connect(m_previewButton, SIGNAL(Clicked()), SLOT(ShowPreview()));
174  if (m_metadataButton)
175  connect(m_metadataButton, SIGNAL(Clicked()), SLOT(ShowMetadataOptions()));
176 
177  if (m_cancelButton)
178  connect(m_cancelButton, SIGNAL(Clicked()), SLOT(Close()));
179  connect(m_saveButton, SIGNAL(Clicked()), SLOT(Save()));
180 
181  if (m_schedInfoButton)
183  if (m_previewButton)
185 
186  if (m_dupmethodList)
187  connect(m_dupmethodList, SIGNAL(itemSelected(MythUIButtonListItem *)),
189  if (m_filtersList)
190  connect(m_filtersList, SIGNAL(itemClicked(MythUIButtonListItem *)),
192  if (m_maxepSpin)
193  connect(m_maxepSpin, SIGNAL(itemSelected(MythUIButtonListItem *)),
195  if (m_recgroupList)
196  connect(m_recgroupList, SIGNAL(LosingFocus()),
197  SLOT(PromptForRecGroup()));
198  if (m_transcodeCheck)
199  connect(m_transcodeCheck, SIGNAL(toggled(bool)),
200  SLOT(TranscodeChanged(bool)));
201 
202  BuildFocusList();
203 
204  if (!m_recordingRule->IsLoaded())
205  {
206  if (m_recInfo)
208  else if (m_recordingRule->m_recordID)
210 
211  if (!m_recordingRule->IsLoaded())
212  {
213  LOG(VB_GENERAL, LOG_ERR,
214  "ScheduleEditor::Create() - Failed to load recording rule");
215  return false;
216  }
217  }
218 
219  if (m_player)
220  m_player->StartEmbedding(QRect());
221 
222  return true;
223 }
224 
226 {
227  if (m_child)
228  m_child->Close();
229 
230  // don't fade the screen if we are returning to the player
231  if (m_player)
232  GetScreenStack()->PopScreen(this, false);
233  else
234  GetScreenStack()->PopScreen(this, true);
235 }
236 
238 {
243 
244  if (!m_loaded)
245  {
246  // Copy this now, it will change briefly after the first item
247  // is inserted into the list by design of
248  // MythUIButtonList::itemSelected()
250 
251  // Rules List
253  {
255  .compare("Default", Qt::CaseInsensitive) != 0)
256  {
258  tr("Delete this recording rule template"),
260  }
264  }
265  else if (m_recordingRule->m_isOverride)
266  {
268  tr("Record this showing with normal options"),
276  }
277  else
278  {
279  bool hasChannel = !m_recordingRule->m_station.isEmpty();
280  bool isManual = (m_recordingRule->m_searchType == kManualSearch);
281 
285  if (hasChannel)
289  if (!isManual)
293  if (!hasChannel || isManual)
297  if (!hasChannel || isManual)
301  if (!isManual)
305  }
306 
308  }
310 
311  InfoMap progMap;
312 
313  m_recordingRule->ToMap(progMap);
314 
315  if (m_recInfo)
316  m_recInfo->ToMap(progMap);
317 
318  SetTextFromMap(progMap);
319 
320  m_loaded = true;
321 }
322 
323 void ScheduleEditor::LoadTemplate(const QString& name)
324 {
326  Load();
327  emit templateLoaded();
328 }
329 
331 {
332  if (!item)
333  return;
334 
335  m_recordingRule->m_type = static_cast<RecordingType>
336  (item->GetData().toInt());
337 
338  bool isScheduled = (m_recordingRule->m_type != kNotRecording &&
340 
341  if (m_schedOptButton)
342  m_schedOptButton->SetEnabled(isScheduled);
343  if (m_filtersButton)
344  m_filtersButton->SetEnabled(isScheduled);
345  if (m_storeOptButton)
346  m_storeOptButton->SetEnabled(isScheduled);
347  if (m_postProcButton)
348  m_postProcButton->SetEnabled(isScheduled);
349  if (m_metadataButton)
350  m_metadataButton->SetEnabled(isScheduled &&
352 
357 }
358 
360 {
362 }
363 
365 {
367 }
368 
370 {
372 }
373 
375 {
377 }
378 
380 {
382 }
383 
385 {
386  if (m_child)
387  m_child->Close();
388 
390  {
391  int recid = m_recordingRule->m_recordID;
392  DeleteRule();
393  if (recid)
394  emit ruleDeleted(recid);
395  Close();
396  return;
397  }
398 
403  m_recordingRule->Save(true);
405 
406  Close();
407 }
408 
410 {
412 }
413 
415 {
418  return;
419 
420  if (m_child)
421  m_child->Close();
422 
424 
426  auto *schedoptedit = new SchedOptEditor(mainStack, *this,
428  if (!schedoptedit->Create())
429  {
430  delete schedoptedit;
431  return;
432  }
433 
435  m_child = schedoptedit;
436  mainStack->AddScreen(schedoptedit);
437 }
438 
440 {
443  return;
444 
445  if (m_child)
446  m_child->Close();
447 
449 
451  auto *storeoptedit = new StoreOptEditor(mainStack, *this,
453  if (!storeoptedit->Create())
454  {
455  delete storeoptedit;
456  return;
457  }
458 
460  m_child = storeoptedit;
461  mainStack->AddScreen(storeoptedit);
462 }
463 
465 {
468  return;
469 
470  if (m_child)
471  m_child->Close();
472 
474 
476  auto *ppedit = new PostProcEditor(mainStack, *this,
478  if (!ppedit->Create())
479  {
480  delete ppedit;
481  return;
482  }
483 
485  m_child = ppedit;
486  mainStack->AddScreen(ppedit);
487 }
488 
490 {
492  return;
493 
494  QString label = tr("Schedule Information");
495 
496  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
497  auto *menuPopup = new MythDialogBox(label, popupStack, "menuPopup");
498 
499  if (menuPopup->Create())
500  {
501  menuPopup->SetReturnEvent(this, "schedinfo");
502 
503  if (m_recInfo)
504  menuPopup->AddButton(tr("Program Details"));
505  menuPopup->AddButton(tr("Upcoming Episodes"));
506  menuPopup->AddButton(tr("Upcoming Recordings"));
508  menuPopup->AddButton(tr("Previously Recorded"));
509 
510  popupStack->AddScreen(menuPopup);
511  }
512  else
513  delete menuPopup;
514 }
515 
516 bool ScheduleEditor::keyPressEvent(QKeyEvent *event)
517 {
518  if (GetFocusWidget()->keyPressEvent(event))
519  return true;
520 
521  QStringList actions;
522  bool handled = GetMythMainWindow()->
523  TranslateKeyPress("TV Frontend", event, actions);
524 
525  for (int i = 0; i < actions.size() && !handled; i++)
526  {
527  QString action = actions[i];
528  handled = true;
529 
530  if (action == "MENU")
531  showMenu();
532  else if (action == "INFO")
533  ShowDetails();
534  else if (action == "GUIDE")
535  ShowGuide();
536  else if (action == "UPCOMING")
538  else if (action == "PREVVIEW")
540  else if (action == "NEXTVIEW")
541  ShowNextView();
542  else
543  handled = false;
544  }
545 
546  if (!handled && MythScreenType::keyPressEvent(event))
547  handled = true;
548 
549  return handled;
550 }
551 
552 void ScheduleEditor::customEvent(QEvent *event)
553 {
554  if (event->type() == DialogCompletionEvent::kEventType)
555  {
556  auto *dce = (DialogCompletionEvent*)(event);
557 
558  QString resultid = dce->GetId();
559  QString resulttext = dce->GetResultText();
560 
561  if (resultid == "menu")
562  {
563  if (resulttext == tr("Main Options"))
564  m_child->Close();
565  if (resulttext == tr("Schedule Options"))
566  ShowSchedOpt();
567  else if (resulttext == tr("Filter Options"))
568  ShowFilters();
569  else if (resulttext == tr("Storage Options"))
570  ShowStoreOpt();
571  else if (resulttext == tr("Post Processing"))
572  ShowPostProc();
573  else if (resulttext == tr("Metadata Options"))
575  else if (resulttext == tr("Use Template"))
577  else if (resulttext == tr("Schedule Info"))
578  ShowSchedInfo();
579  else if (resulttext == tr("Preview Changes"))
580  ShowPreview();
581  }
582  else if (resultid == "templatemenu")
583  {
584  LoadTemplate(resulttext);
585  }
586  else if (resultid == "schedinfo")
587  {
588  if (resulttext == tr("Program Details"))
589  ShowDetails();
590  else if (resulttext == tr("Upcoming Episodes"))
592  else if (resulttext == tr("Upcoming Recordings"))
594  else if (resulttext == tr("Previously Recorded"))
597  }
598  else if (resultid == "newrecgroup")
599  {
600  int groupID = CreateRecordingGroup(resulttext);
601  StoreOptMixin::SetRecGroup(groupID, resulttext);
602  }
603  }
604 }
605 
607 {
609  return;
610 
611  // No rule? Search by title
612  if (m_recordingRule->m_recordID <= 0)
613  {
615  return;
616  }
617 
619  auto *pl = new ProgLister(mainStack, plRecordid,
620  QString::number(m_recordingRule->m_recordID), "");
621 
622  if (pl->Create())
623  mainStack->AddScreen(pl);
624  else
625  delete pl;
626 }
627 
629 {
631  return;
632 
633  // Existing rule and search? Search by rule
634  if (m_recordingRule->m_recordID > 0 &&
637 
638  QString title = m_recordingRule->m_title;
639 
641  title.remove(QRegExp(" \\(.*\\)$"));
642 
644 }
645 
647 {
649  return;
650 
651  if (m_child)
652  {
653  m_child->Save();
654  if (m_view == kSchedOptView)
656  else if (m_view == kStoreOptView)
658  else if (m_view == kPostProcView)
660  }
661 
666 
667  QString ttable = "record_tmp";
668  m_recordingRule->UseTempTable(true, ttable);
669 
671  auto *vsd = new ViewScheduleDiff(mainStack, ttable,
674  if (vsd->Create())
675  mainStack->AddScreen(vsd);
676  else
677  delete vsd;
678 
680 }
681 
683 {
687  return;
688 
689  if (m_child)
690  m_child->Close();
691 
693  auto *rad = new MetadataOptions(mainStack, *this,
695  if (!rad->Create())
696  {
697  delete rad;
698  return;
699  }
700 
702  m_child = rad;
703  mainStack->AddScreen(rad);
704 }
705 
707 {
710  return;
711 
712  if (m_child)
713  m_child->Close();
714 
716 
718  auto *schedfilteredit = new SchedFilterEditor(mainStack, *this,
720  if (!schedfilteredit->Create())
721  {
722  delete schedfilteredit;
723  return;
724  }
725 
727  m_child = schedfilteredit;
728  mainStack->AddScreen(schedfilteredit);
729 }
730 
732 {
735  return;
736 
739  else if ((m_view == kMainView) || (m_view == kMetadataView))
740  ShowPostProc();
741  else if (m_view == kSchedOptView)
742  m_child->Close();
743  else if (m_view == kFilterView)
744  ShowSchedOpt();
745  else if (m_view == kStoreOptView)
746  ShowFilters();
747  else if (m_view == kPostProcView)
748  ShowStoreOpt();
749 }
750 
752 {
755  return;
756 
757  if (m_view == kMainView)
758  ShowSchedOpt();
759  else if (m_view == kSchedOptView)
760  ShowFilters();
761  else if (m_view == kFilterView)
762  ShowStoreOpt();
763  else if (m_view == kStoreOptView)
764  ShowPostProc();
767  else if ((m_view == kPostProcView) || (m_view == kMetadataView))
768  m_child->Close();
769 }
770 
772 {
773  if (m_view == kSchedOptView)
775  else if (m_view == kFilterView)
777  else if (m_view == kStoreOptView)
779  else if (m_view == kPostProcView)
781 
782  m_child = nullptr;
783  m_view = kMainView;
784 }
785 
787 {
788  QString label = tr("Options");
789  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
790  auto *menuPopup = new MythDialogBox(label, popupStack, "menuPopup");
791 
793  RecordingType type = static_cast<RecordingType>(item->GetData().toInt());
794  bool isScheduled = (type != kNotRecording && type != kDontRecord);
795 
796  if (menuPopup->Create())
797  {
798  menuPopup->SetReturnEvent(this, "menu");
799  if (m_view != kMainView)
800  menuPopup->AddButton(tr("Main Options"));
801  if (isScheduled && m_view != kSchedOptView)
802  menuPopup->AddButton(tr("Schedule Options"));
803  if (isScheduled && m_view != kFilterView)
804  menuPopup->AddButton(tr("Filter Options"));
805  if (isScheduled && m_view != kStoreOptView)
806  menuPopup->AddButton(tr("Storage Options"));
807  if (isScheduled && m_view != kPostProcView)
808  menuPopup->AddButton(tr("Post Processing"));
809  if (isScheduled && !m_recordingRule->m_isTemplate &&
811  menuPopup->AddButton(tr("Metadata Options"));
813  menuPopup->AddButton(tr("Schedule Info"));
815  menuPopup->AddButton(tr("Preview Changes"));
816  menuPopup->AddButton(tr("Use Template"));
817  popupStack->AddScreen(menuPopup);
818  }
819  else
820  {
821  delete menuPopup;
822  }
823 }
824 
826 {
827  QStringList templates = RecordingRule::GetTemplateNames();
828  if (templates.empty())
829  {
830  ShowOkPopup(tr("No templates available"));
831  return;
832  }
833 
834  QString label = tr("Template Options");
835  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
836  auto *menuPopup = new MythDialogBox(label, popupStack, "menuPopup");
837 
838  if (menuPopup->Create())
839  {
840  menuPopup->SetReturnEvent(this, "templatemenu");
841  while (!templates.empty())
842  {
843  QString name = templates.front();
844  if (name == "Default")
845  menuPopup->AddButton(tr("Default"));
846  else
847  menuPopup->AddButton(name);
848  templates.pop_front();
849  }
850  popupStack->AddScreen(menuPopup);
851  }
852  else
853  {
854  delete menuPopup;
855  }
856 }
857 
859 
864 SchedEditChild::SchedEditChild(MythScreenStack *parent, const QString &name,
865  ScheduleEditor &editor, RecordingRule &rule,
866  RecordingInfo *recInfo)
867  : MythScreenType(parent, name),
868  m_editor(&editor), m_recordingRule(&rule), m_recInfo(recInfo)
869 {
870 }
871 
872 bool SchedEditChild::keyPressEvent(QKeyEvent *event)
873 {
874  if (GetFocusWidget()->keyPressEvent(event))
875  return true;
876 
877  QStringList actions;
878  bool handled = GetMythMainWindow()->
879  TranslateKeyPress("TV Frontend", event, actions);
880 
881  for (int i = 0; i < actions.size() && !handled; i++)
882  {
883  QString action = actions[i];
884  handled = true;
885 
886  if (action == "MENU")
887  m_editor->showMenu();
888  else if (action == "INFO")
890  else if (action == "UPCOMING")
892  if (action == "ESCAPE")
893  Close();
894  else if (action == "PREVVIEW")
896  else if (action == "NEXTVIEW")
898  else
899  handled = false;
900  }
901 
902  if (!handled && MythScreenType::keyPressEvent(event))
903  handled = true;
904 
905  return handled;
906 }
907 
909  const QString &xmlfile, const QString &winname, bool isTemplate)
910 {
911  if (!LoadWindowFromXML(xmlfile, winname, this))
912  return false;
913 
914  UIUtilW::Assign(this, m_backButton, "back");
915  UIUtilW::Assign(this, m_saveButton, "save");
916  UIUtilW::Assign(this, m_previewButton, "preview");
917 
918  connect(this, SIGNAL(Closing()), m_editor, SLOT(ChildClosing()));
919  connect(m_editor, SIGNAL(templateLoaded()), SLOT(Load()));
920 
921  if (m_backButton)
922  connect(m_backButton, SIGNAL(Clicked()), SLOT(Close()));
923  if (m_saveButton)
924  connect(m_saveButton, SIGNAL(Clicked()), m_editor, SLOT(Save()));
925  if (m_previewButton)
926  connect(m_previewButton, SIGNAL(Clicked()),
927  m_editor, SLOT(ShowPreview()));
928 
929  if (m_previewButton)
930  m_previewButton->SetEnabled(!isTemplate);
931 
932  return true;
933 }
934 
936 {
937  InfoMap progMap;
938 
939  m_recordingRule->ToMap(progMap);
940 
941  if (m_recInfo)
942  m_recInfo->ToMap(progMap);
943 
944  SetTextFromMap(progMap);
945 }
946 
948 {
949  Save();
950  emit Closing();
952 }
953 
955 
962  ScheduleEditor &editor,
963  RecordingRule &rule,
964  RecordingInfo *recInfo)
965  : SchedEditChild(parent, "ScheduleOptionsEditor", editor, rule, recInfo),
966  SchedOptMixin(*this, &rule, &editor)
967 {
968 }
969 
971 {
973  "schedule-ui.xml", "scheduleoptionseditor",
975  {
976  return false;
977  }
978 
979  bool err = false;
980 
981  SchedOptMixin::Create(&err);
982 
983  UIUtilW::Assign(this, m_filtersButton, "filters");
984 
985  if (err)
986  {
987  LOG(VB_GENERAL, LOG_ERR, "SchedOptEditor, theme is missing "
988  "required elements");
989  return false;
990  }
991 
992  if (m_dupmethodList)
993  connect(m_dupmethodList, SIGNAL(itemSelected(MythUIButtonListItem *)),
995 
996  if (m_filtersButton)
997  connect(m_filtersButton, SIGNAL(Clicked()),
998  m_editor, SLOT(ShowFilters()));
999 
1000  BuildFocusList();
1001 
1002  return true;
1003 }
1004 
1006 {
1008  SetTextFromMaps();
1009 }
1010 
1012 {
1014 }
1015 
1017 {
1019 }
1020 
1022 
1029  ScheduleEditor &editor,
1030  RecordingRule &rule,
1031  RecordingInfo *recInfo)
1032  : SchedEditChild(parent, "ScheduleFilterEditor", editor, rule, recInfo),
1033  FilterOptMixin(*this, &rule, &editor)
1034 {
1035 }
1036 
1038 {
1040  "schedule-ui.xml", "schedulefiltereditor",
1042  {
1043  return false;
1044  }
1045 
1046  bool err = false;
1047 
1048  FilterOptMixin::Create(&err);
1049 
1050  if (err)
1051  {
1052  LOG(VB_GENERAL, LOG_ERR, "SchedFilterEditor, theme is missing "
1053  "required elements");
1054  return false;
1055  }
1056 
1057  connect(m_filtersList, SIGNAL(itemClicked(MythUIButtonListItem *)),
1059 
1060  BuildFocusList();
1061 
1062  return true;
1063 }
1064 
1066 {
1068  SetTextFromMaps();
1069 }
1070 
1072 {
1074 }
1075 
1077 {
1079 }
1080 
1082 
1089  ScheduleEditor &editor,
1090  RecordingRule &rule,
1091  RecordingInfo *recInfo)
1092  : SchedEditChild(parent, "StorageOptionsEditor", editor, rule, recInfo),
1093  StoreOptMixin(*this, &rule, &editor)
1094 {
1095 }
1096 
1098 {
1100  "schedule-ui.xml", "storageoptionseditor",
1102  {
1103  return false;
1104  }
1105 
1106  bool err = false;
1107 
1108  StoreOptMixin::Create(&err);
1109 
1110  if (err)
1111  {
1112  LOG(VB_GENERAL, LOG_ERR, "StoreOptEditor, theme is missing "
1113  "required elements");
1114  return false;
1115  }
1116 
1117  if (m_maxepSpin)
1118  connect(m_maxepSpin, SIGNAL(itemSelected(MythUIButtonListItem *)),
1120  if (m_recgroupList)
1121  connect(m_recgroupList, SIGNAL(LosingFocus()),
1122  SLOT(PromptForRecGroup()));
1123 
1124  BuildFocusList();
1125 
1126  return true;
1127 }
1128 
1130 {
1132  SetTextFromMaps();
1133 }
1134 
1136 {
1138 }
1139 
1141 {
1143 }
1144 
1145 void StoreOptEditor::customEvent(QEvent *event)
1146 {
1147  if (event->type() == DialogCompletionEvent::kEventType)
1148  {
1149  auto *dce = (DialogCompletionEvent*)(event);
1150 
1151  QString resultid = dce->GetId();
1152  QString resulttext = dce->GetResultText();
1153 
1154  if (resultid == "newrecgroup")
1155  {
1156  int groupID = CreateRecordingGroup(resulttext);
1157  StoreOptMixin::SetRecGroup(groupID, resulttext);
1158  }
1159  }
1160 }
1161 
1163 {
1165 }
1166 
1168 
1175  ScheduleEditor &editor,
1176  RecordingRule &rule,
1177  RecordingInfo *recInfo)
1178  : SchedEditChild(parent, "PostProcOptionsEditor", editor, rule, recInfo),
1179  PostProcMixin(*this, &rule, &editor)
1180 {
1181 }
1182 
1184 {
1186  "schedule-ui.xml", "postproceditor",
1188  {
1189  return false;
1190  }
1191 
1192  bool err = false;
1193 
1194  PostProcMixin::Create(&err);
1195 
1196  if (err)
1197  {
1198  LOG(VB_GENERAL, LOG_ERR, "PostProcEditor, theme is missing "
1199  "required elements");
1200  return false;
1201  }
1202 
1203  if (m_transcodeCheck)
1204  connect(m_transcodeCheck, SIGNAL(toggled(bool)),
1205  SLOT(TranscodeChanged(bool)));
1206 
1207  BuildFocusList();
1208 
1209  return true;
1210 }
1211 
1213 {
1215  SetTextFromMaps();
1216 }
1217 
1219 {
1221 }
1222 
1224 {
1226 }
1227 
1229 
1236  ScheduleEditor &editor,
1237  RecordingRule &rule,
1238  RecordingInfo *recInfo)
1239  : SchedEditChild(parent, "MetadataOptions", editor, rule, recInfo)
1240 {
1241  m_popupStack = GetMythMainWindow()->GetStack("popup stack");
1242 
1243  m_metadataFactory = new MetadataFactory(this);
1244  m_imageLookup = new MetadataDownload(this);
1246 
1249 }
1250 
1252 {
1253  if (m_imageLookup)
1254  {
1255  m_imageLookup->cancel();
1256  delete m_imageLookup;
1257  m_imageLookup = nullptr;
1258  }
1259 
1260  if (m_imageDownload)
1261  {
1263  delete m_imageDownload;
1264  m_imageDownload = nullptr;
1265  }
1266 }
1267 
1269 {
1271  "schedule-ui.xml", "metadataoptions",
1273  {
1274  return false;
1275  }
1276 
1277  bool err = false;
1278 
1279  UIUtilE::Assign(this, m_inetrefEdit, "inetref_edit", &err);
1280  UIUtilW::Assign(this, m_inetrefClear, "inetref_clear", &err);
1281  UIUtilE::Assign(this, m_seasonSpin, "season_spinbox", &err);
1282  UIUtilE::Assign(this, m_episodeSpin, "episode_spinbox", &err);
1283  UIUtilE::Assign(this, m_queryButton, "query_button", &err);
1284  UIUtilE::Assign(this, m_localFanartButton, "local_fanart_button", &err);
1285  UIUtilE::Assign(this, m_localCoverartButton, "local_coverart_button", &err);
1286  UIUtilE::Assign(this, m_localBannerButton, "local_banner_button", &err);
1287  UIUtilE::Assign(this, m_onlineFanartButton, "online_fanart_button", &err);
1288  UIUtilE::Assign(this, m_onlineCoverartButton, "online_coverart_button", &err);
1289  UIUtilE::Assign(this, m_onlineBannerButton, "online_banner_button", &err);
1290  UIUtilW::Assign(this, m_fanart, "fanart");
1291  UIUtilW::Assign(this, m_coverart, "coverart");
1292  UIUtilW::Assign(this, m_banner, "banner");
1293 
1294  if (err)
1295  {
1296  LOG(VB_GENERAL, LOG_ERR, "MetadataOptions, theme is missing "
1297  "required elements");
1298  return false;
1299  }
1300 
1301  connect(m_inetrefClear, SIGNAL(Clicked()),
1302  SLOT(ClearInetref()));
1303  connect(m_queryButton, SIGNAL(Clicked()),
1304  SLOT(PerformQuery()));
1305  connect(m_localFanartButton, SIGNAL(Clicked()),
1306  SLOT(SelectLocalFanart()));
1307  connect(m_localCoverartButton, SIGNAL(Clicked()),
1308  SLOT(SelectLocalCoverart()));
1309  connect(m_localBannerButton, SIGNAL(Clicked()),
1310  SLOT(SelectLocalBanner()));
1311  connect(m_onlineFanartButton, SIGNAL(Clicked()),
1312  SLOT(SelectOnlineFanart()));
1313  connect(m_onlineCoverartButton, SIGNAL(Clicked()),
1314  SLOT(SelectOnlineCoverart()));
1315  connect(m_onlineBannerButton, SIGNAL(Clicked()),
1316  SLOT(SelectOnlineBanner()));
1317 
1318  connect(m_seasonSpin, SIGNAL(itemSelected(MythUIButtonListItem*)),
1319  SLOT(ValuesChanged()));
1320 
1321  // InetRef
1323 
1324  // Season
1325  m_seasonSpin->SetRange(0,9999,1,5);
1327 
1328  // Episode
1329  m_episodeSpin->SetRange(0,9999,1,10);
1331 
1332  if (m_coverart)
1333  {
1335  m_coverart->Load();
1336  }
1337 
1338  if (m_fanart)
1339  {
1341  m_fanart->Load();
1342  }
1343 
1344  if (m_banner)
1345  {
1347  m_banner->Load();
1348  }
1349 
1350  BuildFocusList();
1351 
1352  return true;
1353 }
1354 
1356 {
1357  SetTextFromMaps();
1358 }
1359 
1360 void MetadataOptions::CreateBusyDialog(const QString& title)
1361 {
1362  if (m_busyPopup)
1363  return;
1364 
1365  const QString& message = title;
1366 
1367  m_busyPopup = new MythUIBusyDialog(message, m_popupStack,
1368  "metaoptsdialog");
1369 
1370  if (m_busyPopup->Create())
1372 }
1373 
1375 {
1376  m_recordingRule->m_inetref.clear();
1378 }
1379 
1381 {
1382  CreateBusyDialog(tr("Trying to manually find this "
1383  "recording online..."));
1384 
1386 
1387  lookup->SetAutomatic(false);
1388  m_metadataFactory->Lookup(lookup);
1389 }
1390 
1392 {
1393  QueryComplete(lookup);
1394 }
1395 
1398 {
1399  QString msg = tr("Downloading selected artwork...");
1400  CreateBusyDialog(msg);
1401 
1402  auto *lookup = new MetadataLookup();
1403 
1404  lookup->SetType(kMetadataVideo);
1405  lookup->SetHost(gCoreContext->GetMasterHostName());
1406  lookup->SetAutomatic(true);
1407  lookup->SetData(qVariantFromValue<VideoArtworkType>(type));
1408 
1409  ArtworkMap downloads;
1410  downloads.insert(type, info);
1411  lookup->SetDownloads(downloads);
1412  lookup->SetAllowOverwrites(true);
1413  lookup->SetTitle(m_recordingRule->m_title);
1414  lookup->SetSubtitle(m_recordingRule->m_subtitle);
1415  lookup->SetInetref(m_inetrefEdit->GetText());
1416  lookup->SetSeason(m_seasonSpin->GetIntValue());
1417  lookup->SetEpisode(m_episodeSpin->GetIntValue());
1418 
1419  m_imageDownload->addDownloads(lookup);
1420 }
1421 
1423 {
1424  if (!CanSetArtwork())
1425  return;
1426 
1427  QString url = generate_file_url("Fanart",
1429  "");
1430  FindImagePopup(url,"",*this, "fanart");
1431 }
1432 
1434 {
1435  if (!CanSetArtwork())
1436  return;
1437 
1438  QString url = generate_file_url("Coverart",
1440  "");
1441  FindImagePopup(url,"",*this, "coverart");
1442 }
1443 
1445 {
1446  if (!CanSetArtwork())
1447  return;
1448 
1449  QString url = generate_file_url("Banners",
1451  "");
1452  FindImagePopup(url,"",*this, "banner");
1453 }
1454 
1456 {
1458 }
1459 
1461 {
1463 }
1464 
1466 {
1468 }
1469 
1471 {
1472  // Season
1473  if (m_seasonSpin)
1475 
1476  // Episode
1477  if (m_episodeSpin)
1479 
1480  // InetRef
1481  if (m_inetrefEdit)
1483 }
1484 
1486 {
1487  if (!lookup)
1488  return;
1489 
1490  // InetRef
1491  m_inetrefEdit->SetText(lookup->GetInetref());
1492 
1493  // Season
1494  m_seasonSpin->SetValue(lookup->GetSeason());
1495 
1496  // Episode
1497  m_episodeSpin->SetValue(lookup->GetEpisode());
1498 
1499  InfoMap metadataMap;
1500  lookup->toMap(metadataMap);
1501  SetTextFromMap(metadataMap);
1502 }
1503 
1505  const QString &prefixAlt,
1506  QObject &inst,
1507  const QString &returnEvent)
1508 {
1509  QString fp;
1510 
1511  if (prefix.startsWith("myth://"))
1512  fp = prefix;
1513  else
1514  fp = prefix.isEmpty() ? prefixAlt : prefix;
1515 
1516  MythScreenStack *popupStack =
1517  GetMythMainWindow()->GetStack("popup stack");
1518 
1519  auto *fb = new MythUIFileBrowser(popupStack, fp);
1520  fb->SetNameFilter(GetSupportedImageExtensionFilter());
1521  if (fb->Create())
1522  {
1523  fb->SetReturnEvent(&inst, returnEvent);
1524  popupStack->AddScreen(fb);
1525  }
1526  else
1527  delete fb;
1528 }
1529 
1531 {
1532  QStringList ret;
1533 
1534  QList<QByteArray> exts = QImageReader::supportedImageFormats();
1535  for (QList<QByteArray>::iterator p = exts.begin(); p != exts.end(); ++p)
1536  {
1537  ret.append(QString("*.").append(*p));
1538  }
1539 
1540  return ret;
1541 }
1542 
1544 {
1545  if (m_inetrefEdit->GetText().isEmpty())
1546  {
1547  ShowOkPopup(tr("You must set a reference number "
1548  "on this rule to set artwork. For items "
1549  "without a metadata source, you can set "
1550  "any unique value."));
1551  return false;
1552  }
1553 
1554  return true;
1555 }
1556 
1558 {
1559  auto *lookup = new MetadataLookup();
1560  lookup->SetStep(kLookupSearch);
1561  lookup->SetType(mtype);
1563 
1564  if (type == kUnknownVideo)
1565  {
1567  (m_seasonSpin->GetIntValue() == 0 &&
1568  m_episodeSpin->GetIntValue() == 0))
1569  {
1570  lookup->SetSubtype(kProbableMovie);
1571  }
1572  else
1573  {
1574  lookup->SetSubtype(kProbableTelevision);
1575  }
1576  }
1577  else
1578  {
1579  // we could determine the type from the inetref
1580  lookup->SetSubtype(type);
1581  }
1582  lookup->SetAllowGeneric(true);
1583  lookup->SetHandleImages(false);
1584  lookup->SetHost(gCoreContext->GetMasterHostName());
1585  lookup->SetTitle(m_recordingRule->m_title);
1586  lookup->SetSubtitle(m_recordingRule->m_subtitle);
1587  lookup->SetInetref(m_inetrefEdit->GetText());
1588  lookup->SetCollectionref(m_inetrefEdit->GetText());
1589  lookup->SetSeason(m_seasonSpin->GetIntValue());
1590  lookup->SetEpisode(m_episodeSpin->GetIntValue());
1591 
1592  return lookup;
1593 }
1594 
1596 {
1597  if (!CanSetArtwork())
1598  return;
1599 
1600  QString msg = tr("Searching for available artwork...");
1601  CreateBusyDialog(msg);
1602 
1604 
1605  lookup->SetAutomatic(true);
1606  lookup->SetData(qVariantFromValue<VideoArtworkType>(type));
1607  m_imageLookup->addLookup(lookup);
1608 }
1609 
1611 {
1612  if (!lookup)
1613  return;
1614 
1615  if (m_busyPopup)
1616  {
1617  m_busyPopup->Close();
1618  m_busyPopup = nullptr;
1619  }
1620 
1621  auto type = lookup->GetData().value<VideoArtworkType>();
1622  ArtworkList list = lookup->GetArtwork(type);
1623 
1624  if (list.isEmpty())
1625  {
1626  MythWarningNotification n(tr("No image found"), tr("Schedule Editor"));
1628  return;
1629  }
1630 
1631  auto *resultsdialog = new ImageSearchResultsDialog(m_popupStack, list, type);
1632 
1633  connect(resultsdialog, SIGNAL(haveResult(ArtworkInfo, VideoArtworkType)),
1635 
1636  if (resultsdialog->Create())
1637  m_popupStack->AddScreen(resultsdialog);
1638 }
1639 
1641 {
1642  if (!lookup)
1643  return;
1644 
1645  DownloadMap map = lookup->GetDownloads();
1646 
1647  if (map.isEmpty())
1648  return;
1649 
1650  for (DownloadMap::const_iterator i = map.begin(); i != map.end(); ++i)
1651  {
1652  VideoArtworkType type = i.key();
1653  const ArtworkInfo& info = i.value();
1654 
1655  if (type == kArtworkCoverart)
1656  m_artworkMap.replace(kArtworkCoverart, info);
1657  else if (type == kArtworkFanart)
1658  m_artworkMap.replace(kArtworkFanart, info);
1659  else if (type == kArtworkBanner)
1660  m_artworkMap.replace(kArtworkBanner, info);
1661  }
1662 
1665 
1666  ValuesChanged();
1667 }
1668 
1670 {
1673 
1674  if (m_coverart)
1675  {
1677  m_coverart->Load();
1678  }
1679 
1680  if (m_fanart)
1681  {
1683  m_fanart->Load();
1684  }
1685 
1686  if (m_banner)
1687  {
1689  m_banner->Load();
1690  }
1691 }
1692 
1693 void MetadataOptions::customEvent(QEvent *levent)
1694 {
1695  if (levent->type() == MetadataFactoryMultiResult::kEventType)
1696  {
1697  if (m_busyPopup)
1698  {
1699  m_busyPopup->Close();
1700  m_busyPopup = nullptr;
1701  }
1702 
1703  auto *mfmr = dynamic_cast<MetadataFactoryMultiResult*>(levent);
1704  if (!mfmr)
1705  return;
1706 
1707  MetadataLookupList list = mfmr->m_results;
1708 
1709  if (list.count() > 1)
1710  {
1711  int yearindex = -1;
1712 
1713  for (int p = 0; p != list.size(); ++p)
1714  {
1715  if (!m_recordingRule->m_seriesid.isEmpty() &&
1716  m_recordingRule->m_seriesid == (list[p])->GetTMSref())
1717  {
1718  MetadataLookup *lookup = list[p];
1719  QueryComplete(lookup);
1720  return;
1721  }
1722  if (m_recInfo &&
1724  (list[p])->GetYear() != 0 &&
1725  m_recInfo->GetYearOfInitialRelease() == (list[p])->GetYear())
1726  {
1727  if (yearindex > -1)
1728  {
1729  LOG(VB_GENERAL, LOG_INFO, "Multiple results matched on year. No definite "
1730  "match could be found based on year alone.");
1731  yearindex = -2;
1732  }
1733  else if (yearindex == -1)
1734  {
1735  LOG(VB_GENERAL, LOG_INFO, "Matched based on year. ");
1736  yearindex = p;
1737  }
1738  }
1739  }
1740 
1741  if (yearindex > -1)
1742  {
1743  MetadataLookup *lookup = list[yearindex];
1744  QueryComplete(lookup);
1745  return;
1746  }
1747 
1748  LOG(VB_GENERAL, LOG_INFO, "Falling through to selection dialog.");
1749  auto *resultsdialog = new MetadataResultsDialog(m_popupStack, list);
1750 
1751  connect(resultsdialog, SIGNAL(haveResult(RefCountHandler<MetadataLookup>)),
1753  Qt::QueuedConnection);
1754 
1755  if (resultsdialog->Create())
1756  m_popupStack->AddScreen(resultsdialog);
1757  }
1758  }
1759  else if (levent->type() == MetadataFactorySingleResult::kEventType)
1760  {
1761  if (m_busyPopup)
1762  {
1763  m_busyPopup->Close();
1764  m_busyPopup = nullptr;
1765  }
1766 
1767  auto *mfsr = dynamic_cast<MetadataFactorySingleResult*>(levent);
1768  if (!mfsr)
1769  return;
1770 
1771  MetadataLookup *lookup = mfsr->m_result;
1772 
1773  if (!lookup)
1774  return;
1775 
1776  QueryComplete(lookup);
1777  }
1778  else if (levent->type() == MetadataFactoryNoResult::kEventType)
1779  {
1780  if (m_busyPopup)
1781  {
1782  m_busyPopup->Close();
1783  m_busyPopup = nullptr;
1784  }
1785 
1786  auto *mfnr = dynamic_cast<MetadataFactoryNoResult*>(levent);
1787  if (!mfnr)
1788  return;
1789 
1790  QString title = tr("No match found for this recording. You can "
1791  "try entering a TVDB/TMDB number, season, and "
1792  "episode manually.");
1793 
1794  auto *okPopup = new MythConfirmationDialog(m_popupStack, title, false);
1795 
1796  if (okPopup->Create())
1797  m_popupStack->AddScreen(okPopup);
1798  }
1799  else if (levent->type() == MetadataLookupEvent::kEventType)
1800  {
1801  if (m_busyPopup)
1802  {
1803  m_busyPopup->Close();
1804  m_busyPopup = nullptr;
1805  }
1806 
1807  auto *lue = (MetadataLookupEvent *)levent;
1808 
1809  MetadataLookupList lul = lue->m_lookupList;
1810 
1811  if (lul.isEmpty())
1812  return;
1813 
1814  if (lul.count() >= 1)
1815  {
1816  OnArtworkSearchDone(lul[0]);
1817  }
1818  }
1819  else if (levent->type() == MetadataLookupFailure::kEventType)
1820  {
1821  if (m_busyPopup)
1822  {
1823  m_busyPopup->Close();
1824  m_busyPopup = nullptr;
1825  }
1826 
1827  auto *luf = (MetadataLookupFailure *)levent;
1828 
1829  MetadataLookupList lul = luf->m_lookupList;
1830 
1831  if (!lul.empty())
1832  {
1833  QString title = tr("This number, season, and episode combination "
1834  "does not appear to be valid (or the site may "
1835  "be down). Check your information and try "
1836  "again.");
1837 
1838  auto *okPopup = new MythConfirmationDialog(m_popupStack, title, false);
1839 
1840  if (okPopup->Create())
1841  m_popupStack->AddScreen(okPopup);
1842  }
1843  }
1844  else if (levent->type() == ImageDLEvent::kEventType)
1845  {
1846  if (m_busyPopup)
1847  {
1848  m_busyPopup->Close();
1849  m_busyPopup = nullptr;
1850  }
1851 
1852  auto *ide = (ImageDLEvent *)levent;
1853 
1854  MetadataLookup *lookup = ide->m_item;
1855 
1856  if (!lookup)
1857  return;
1858 
1859  HandleDownloadedImages(lookup);
1860  }
1861  else if (levent->type() == ImageDLFailureEvent::kEventType)
1862  {
1863  if (m_busyPopup)
1864  {
1865  m_busyPopup->Close();
1866  m_busyPopup = nullptr;
1867  }
1868  MythErrorNotification n(tr("Failed to retrieve image(s)"),
1869  tr("Schedule Editor"),
1870  tr("Check logs"));
1872  }
1873  else if (levent->type() == DialogCompletionEvent::kEventType)
1874  {
1875  auto *dce = (DialogCompletionEvent*)(levent);
1876 
1877  const QString resultid = dce->GetId();
1878  ArtworkInfo info;
1879  info.url = dce->GetResultText();
1880 
1881  if (resultid == "coverart")
1882  {
1883  m_artworkMap.replace(kArtworkCoverart, info);
1884  }
1885  else if (resultid == "fanart")
1886  {
1887  m_artworkMap.replace(kArtworkFanart, info);
1888  }
1889  else if (resultid == "banner")
1890  {
1891  m_artworkMap.replace(kArtworkBanner, info);
1892  }
1893 
1896 
1897  ValuesChanged();
1898  }
1899 
1900 }
1901 
1903 
1910  SchedOptMixin *other)
1911  : m_screen(&screen), m_rule(rule), m_other(other),
1912  m_haveRepeats(gCoreContext->GetBoolSetting("HaveRepeats", false))
1913 {
1914 }
1915 
1916 void SchedOptMixin::Create(bool *err)
1917 {
1918  if (!m_rule)
1919  return;
1920 
1921  if (m_other && !m_other->m_prioritySpin)
1922  UIUtilE::Assign(m_screen, m_prioritySpin, "priority", err);
1923  else
1924  UIUtilW::Assign(m_screen, m_prioritySpin, "priority");
1925 
1927  UIUtilE::Assign(m_screen, m_startoffsetSpin, "startoffset", err);
1928  else
1929  UIUtilW::Assign(m_screen, m_startoffsetSpin, "startoffset");
1930 
1931  if (m_other && !m_other->m_endoffsetSpin)
1932  UIUtilE::Assign(m_screen, m_endoffsetSpin, "endoffset", err);
1933  else
1934  UIUtilW::Assign(m_screen, m_endoffsetSpin, "endoffset");
1935 
1936  if (m_other && !m_other->m_dupmethodList)
1937  UIUtilE::Assign(m_screen, m_dupmethodList, "dupmethod", err);
1938  else
1939  UIUtilW::Assign(m_screen, m_dupmethodList, "dupmethod");
1940 
1941  if (m_other && !m_other->m_dupscopeList)
1942  UIUtilE::Assign(m_screen, m_dupscopeList, "dupscope", err);
1943  else
1944  UIUtilW::Assign(m_screen, m_dupscopeList, "dupscope");
1945 
1946  if (m_other && !m_other->m_inputList)
1947  UIUtilE::Assign(m_screen, m_inputList, "input", err);
1948  else
1950 
1952  UIUtilE::Assign(m_screen, m_ruleactiveCheck, "ruleactive", err);
1953  else
1954  UIUtilW::Assign(m_screen, m_ruleactiveCheck, "ruleactive");
1955 
1956  UIUtilW::Assign(m_screen, m_newrepeatList, "newrepeat");
1957 }
1958 
1960 {
1961  if (!m_rule)
1962  return;
1963 
1964  // Priority
1965  if (m_prioritySpin)
1966  {
1967  if (!m_loaded)
1968  m_prioritySpin->SetRange(-99,99,1,5);
1970  }
1971 
1972  // Start Offset
1973  if (m_startoffsetSpin)
1974  {
1975  if (!m_loaded)
1976  m_startoffsetSpin->SetRange(480,-480,1,10);
1978  }
1979 
1980  // End Offset
1981  if (m_endoffsetSpin)
1982  {
1983  if (!m_loaded)
1984  m_endoffsetSpin->SetRange(-480,480,1,10);
1986  }
1987 
1988  // Duplicate Match Type
1989  if (m_dupmethodList)
1990  {
1991  if (!m_loaded)
1992  {
1994 
2010 
2011  m_rule->m_dupMethod = dupMethod;
2012  }
2014  }
2015 
2016  // Duplicate Matching Scope
2017  if (m_dupscopeList)
2018  {
2019  if (!m_loaded)
2020  {
2030  if (m_haveRepeats && !m_newrepeatList &&
2032  {
2036  }
2037  }
2039  }
2040 
2041  // Preferred Input
2042  if (m_inputList)
2043  {
2044  if (!m_loaded)
2045  {
2047  QObject::tr("Use any available input"),
2048  qVariantFromValue(0));
2049 
2050  vector<uint> inputids = CardUtil::GetSchedInputList();
2051  for (size_t i = 0; i < inputids.size(); ++i)
2052  {
2054  QObject::tr("Prefer input %1")
2055  .arg(CardUtil::GetDisplayName(inputids[i])), inputids[i]);
2056  }
2057  }
2059  }
2060 
2061  // Active/Disabled
2062  if (m_ruleactiveCheck)
2063  {
2065  }
2066 
2067  // Record new and repeat
2068  if (m_newrepeatList)
2069  {
2070  if (!m_loaded)
2071  {
2073  QObject::tr("Record new and repeat "
2074  "episodes"), ENUM_TO_QVARIANT(0));
2076  QObject::tr("Record new episodes only"),
2078  }
2080  (m_rule->m_dupIn & kDupsNewEpi));
2081  }
2082 
2083  m_loaded = true;
2084 
2085  RuleChanged();
2086 }
2087 
2089 {
2090  if (!m_rule)
2091  return;
2092 
2093  if (m_prioritySpin)
2095  if (m_startoffsetSpin)
2097  if (m_endoffsetSpin)
2099  if (m_dupmethodList)
2100  m_rule->m_dupMethod = static_cast<RecordingDupMethodType>
2101  (m_dupmethodList->GetDataValue().toInt());
2102  if (m_dupscopeList)
2103  {
2104  int mask = ((m_other && m_other->m_newrepeatList) ||
2105  m_newrepeatList) ? kDupsInAll : ~0;
2106  int val = ((m_rule->m_dupIn & ~mask) |
2107  m_dupscopeList->GetDataValue().toInt());
2108  m_rule->m_dupIn = static_cast<RecordingDupInType>(val);
2109  }
2110  if (m_inputList)
2112  if (m_ruleactiveCheck)
2114  if (m_newrepeatList)
2115  {
2116  int val = ((m_rule->m_dupIn & ~kDupsNewEpi) |
2117  m_newrepeatList->GetDataValue().toInt());
2118  m_rule->m_dupIn = static_cast<RecordingDupInType>(val);
2119  }
2120 }
2121 
2123 {
2124  if (!m_rule)
2125  return;
2126 
2127  bool isScheduled = (m_rule->m_type != kNotRecording &&
2128  m_rule->m_type != kDontRecord);
2129  bool isSingle = (m_rule->m_type == kSingleRecord ||
2131 
2132  if (m_prioritySpin)
2133  m_prioritySpin->SetEnabled(isScheduled);
2134  if (m_startoffsetSpin)
2135  m_startoffsetSpin->SetEnabled(isScheduled);
2136  if (m_endoffsetSpin)
2137  m_endoffsetSpin->SetEnabled(isScheduled);
2138  if (m_dupmethodList)
2139  m_dupmethodList->SetEnabled(isScheduled && !isSingle);
2140  if (m_dupscopeList)
2141  m_dupscopeList->SetEnabled(isScheduled && !isSingle &&
2143  if (m_inputList)
2144  m_inputList->SetEnabled(isScheduled);
2145  if (m_ruleactiveCheck)
2146  m_ruleactiveCheck->SetEnabled(isScheduled);
2147  if (m_newrepeatList)
2148  m_newrepeatList->SetEnabled(isScheduled && !isSingle && m_haveRepeats);
2149 }
2150 
2152 {
2153  if (!item || !m_rule)
2154  return;
2155 
2156  m_rule->m_dupMethod = static_cast<RecordingDupMethodType>
2157  (item->GetData().toInt());
2158 
2159  if (m_dupscopeList)
2161 }
2162 
2164 
2170 void FilterOptMixin::Create(bool *err)
2171 {
2172  if (!m_rule)
2173  return;
2174 
2175  if (m_other && !m_other->m_filtersList)
2176  UIUtilE::Assign(m_screen, m_filtersList, "filters", err);
2177  else
2178  UIUtilW::Assign(m_screen, m_filtersList, "filters");
2179 
2180  UIUtilW::Assign(m_screen, m_activeFiltersList, "activefilters");
2181  if (m_activeFiltersList)
2183 }
2184 
2186 {
2187  if (!m_rule)
2188  return;
2189 
2190  if (!m_loaded)
2191  {
2192  MSqlQuery query(MSqlQuery::InitCon());
2193 
2194  query.prepare("SELECT filterid, description, newruledefault "
2195  "FROM recordfilter ORDER BY filterid");
2196 
2197  if (query.exec())
2198  {
2199  while (query.next())
2200  {
2201  m_descriptions << QObject::tr(query.value(1).toString()
2202  .toUtf8().constData());
2203  }
2204  }
2205  m_loaded = true;
2206  }
2207 
2208  if (m_activeFiltersList)
2210 
2211  MythUIButtonListItem *button = nullptr;
2212  QStringList::iterator Idesc;
2213  int idx = 0;
2214  bool not_empty = m_filtersList && !m_filtersList->IsEmpty();
2215  for (Idesc = m_descriptions.begin(), idx = 0;
2216  Idesc != m_descriptions.end(); ++Idesc, ++idx)
2217  {
2218  bool active = (m_rule->m_filter & (1 << idx)) != 0U;
2219  if (m_filtersList)
2220  {
2221  if (not_empty)
2222  button = m_filtersList->GetItemAt(idx);
2223  else
2224  button = new MythUIButtonListItem(m_filtersList, *Idesc, idx);
2225  button->setCheckable(true);
2228  }
2229  if (active && m_activeFiltersList)
2230  {
2231  /* Create a simple list of active filters the theme can
2232  use for informational purposes. */
2234  *Idesc, idx);
2235  button->setCheckable(false);
2236  }
2237  }
2238 
2240  {
2242  QObject::tr("None"), idx);
2243  button->setCheckable(false);
2244  }
2245 
2246  RuleChanged();
2247 }
2248 
2250 {
2251  if (!m_rule || !m_filtersList)
2252  return;
2253 
2254  // Iterate through button list, and build the mask
2255  uint32_t filter_mask = 0;
2256 
2257  int end = m_filtersList->GetCount();
2258  for (int idx = 0; idx < end; ++idx)
2259  {
2261  if (button != nullptr &&
2263  filter_mask |= (1 << button->GetData().value<uint32_t>());
2264  }
2265  m_rule->m_filter = filter_mask;
2266 }
2267 
2269 {
2270  if (!m_rule)
2271  return;
2272 
2273  bool enabled = m_rule->m_type != kNotRecording &&
2275  if (m_filtersList)
2276  m_filtersList->SetEnabled(enabled);
2277  if (m_activeFiltersList)
2278  m_activeFiltersList->SetEnabled(enabled);
2279 }
2280 
2282 {
2286 }
2287 
2288 
2290 
2296 void StoreOptMixin::Create(bool *err)
2297 {
2298  if (!m_rule)
2299  return;
2300 
2301  if (m_other && !m_other->m_recprofileList)
2302  UIUtilE::Assign(m_screen, m_recprofileList, "recprofile", err);
2303  else
2304  UIUtilW::Assign(m_screen, m_recprofileList, "recprofile");
2305 
2306  if (m_other && !m_other->m_recgroupList)
2307  UIUtilE::Assign(m_screen, m_recgroupList, "recgroup", err);
2308  else
2309  UIUtilW::Assign(m_screen, m_recgroupList, "recgroup");
2310 
2312  UIUtilE::Assign(m_screen, m_storagegroupList, "storagegroup", err);
2313  else
2314  UIUtilW::Assign(m_screen, m_storagegroupList, "storagegroup");
2315 
2316  if (m_other && !m_other->m_playgroupList)
2317  UIUtilE::Assign(m_screen, m_playgroupList, "playgroup", err);
2318  else
2319  UIUtilW::Assign(m_screen, m_playgroupList, "playgroup");
2320 
2321  if (m_other && !m_other->m_maxepSpin)
2322  UIUtilE::Assign(m_screen, m_maxepSpin, "maxepisodes", err);
2323  else
2324  UIUtilW::Assign(m_screen, m_maxepSpin, "maxepisodes");
2325 
2327  UIUtilE::Assign(m_screen, m_maxbehaviourList, "maxnewest", err);
2328  else
2330 
2332  UIUtilE::Assign(m_screen, m_autoexpireCheck, "autoexpire", err);
2333  else
2334  UIUtilW::Assign(m_screen, m_autoexpireCheck, "autoexpire");
2335 }
2336 
2338 {
2339  if (!m_rule)
2340  return;
2341 
2342  QString label;
2343  QStringList groups;
2344  QStringList::Iterator it;
2345  MSqlQuery query(MSqlQuery::InitCon());
2346 
2347  // Recording Profile
2348  if (m_recprofileList)
2349  {
2350  if (!m_loaded)
2351  {
2352  label = QObject::tr("Record using the %1 profile");
2353 
2355  label.arg(QObject::tr("Default")),
2356  qVariantFromValue(QString("Default")));
2357  // LiveTV profile - it's for LiveTV not scheduled recordings??
2359  label.arg(QObject::tr("LiveTV")),
2360  qVariantFromValue(QString("LiveTV")));
2362  label.arg(QObject::tr("High Quality")),
2363  qVariantFromValue(QString("High Quality")));
2365  label.arg(QObject::tr("Low Quality")),
2366  qVariantFromValue(QString("Low Quality")));
2367  }
2369  }
2370 
2371  // Recording Group
2372  if (m_recgroupList)
2373  {
2374  if (!m_loaded)
2375  {
2376  label = QObject::tr("Include in the \"%1\" recording group");
2378  QObject::tr("Create a new recording group"),
2379  qVariantFromValue(QString("__NEW_GROUP__")));
2380 
2381  query.prepare("SELECT recgroupid, recgroup FROM recgroups "
2382  "WHERE recgroup <> 'Deleted' AND "
2383  " recgroup <> 'LiveTV' "
2384  "ORDER BY special DESC, recgroup ASC"); // Special groups first
2385  if (query.exec())
2386  {
2387  while (query.next())
2388  {
2389  int id = query.value(0).toInt();
2390  QString name = query.value(1).toString();
2391 
2392  if (name == "Default")
2393  name = QObject::tr("Default");
2394  new MythUIButtonListItem(m_recgroupList, label.arg(name),
2395  qVariantFromValue(id));
2396  }
2397  }
2398 
2399  }
2401  }
2402 
2403  // Storage Group
2404  if (m_storagegroupList)
2405  {
2406  if (!m_loaded)
2407  {
2408  label = QObject::tr("Store in the \"%1\" storage group");
2410  label.arg(QObject::tr("Default")),
2411  qVariantFromValue(QString("Default")));
2412 
2414  for (it = groups.begin(); it != groups.end(); ++it)
2415  {
2416  if ((*it).compare("Default", Qt::CaseInsensitive) != 0)
2418  label.arg(*it), qVariantFromValue(*it));
2419  }
2420  }
2422  }
2423 
2424  // Playback Group
2425  if (m_playgroupList)
2426  {
2427  if (!m_loaded)
2428  {
2429  label = QObject::tr("Use \"%1\" playback group settings");
2431  label.arg(QObject::tr("Default")),
2432  qVariantFromValue(QString("Default")));
2433 
2434  groups = PlayGroup::GetNames();
2435  for (it = groups.begin(); it != groups.end(); ++it)
2436  {
2437  new MythUIButtonListItem(m_playgroupList, label.arg(*it),
2438  qVariantFromValue(*it));
2439  }
2440  }
2442  }
2443 
2444  // Max Episodes
2445  if (m_maxepSpin)
2446  {
2447  if (!m_loaded)
2448  {
2449  int maxEpisodes = m_rule->m_maxEpisodes;
2450  m_maxepSpin->SetRange(0,100,1,5);
2451  m_rule->m_maxEpisodes = maxEpisodes;
2452  }
2454  }
2455 
2456  // Max Episode Behaviour
2457  if (m_maxbehaviourList)
2458  {
2459  if (!m_loaded)
2460  {
2462  QObject::tr("Don't record if this would exceed the max "
2463  "episodes"), qVariantFromValue(false));
2465  QObject::tr("Delete oldest if this would exceed the max "
2466  "episodes"), qVariantFromValue(true));
2467  }
2469  }
2470 
2471  // Auto-Expire
2472  if (m_autoexpireCheck)
2473  {
2475  }
2476 
2477  m_loaded = true;
2478 
2479  RuleChanged();
2480 }
2481 
2483 {
2484  if (!m_rule)
2485  return;
2486 
2487  if (m_recprofileList)
2489 
2490  if (m_recgroupList)
2491  {
2492  // If the user selected 'Create a new regroup' but failed to enter a
2493  // name when prompted, restore the original value
2494  if (m_recgroupList->GetDataValue().toString() == "__NEW_GROUP__")
2497  }
2498 
2499  if (m_storagegroupList)
2501 
2502  if (m_playgroupList)
2504 
2505  if (m_maxepSpin)
2507 
2508  if (m_maxbehaviourList)
2510 
2511  if (m_autoexpireCheck)
2513 }
2514 
2516 {
2517  if (!m_rule)
2518  return;
2519 
2520  bool isScheduled = (m_rule->m_type != kNotRecording &&
2521  m_rule->m_type != kDontRecord);
2522  bool isSingle = (m_rule->m_type == kSingleRecord ||
2524 
2525  if (m_recprofileList)
2526  m_recprofileList->SetEnabled(isScheduled);
2527  if (m_recgroupList)
2528  m_recgroupList->SetEnabled(isScheduled);
2529  if (m_storagegroupList)
2530  m_storagegroupList->SetEnabled(isScheduled);
2531  if (m_playgroupList)
2532  m_playgroupList->SetEnabled(isScheduled);
2533  if (m_maxepSpin)
2534  m_maxepSpin->SetEnabled(isScheduled && !isSingle);
2535  if (m_maxbehaviourList)
2536  m_maxbehaviourList->SetEnabled(isScheduled && !isSingle &&
2537  m_rule->m_maxEpisodes != 0);
2538  if (m_autoexpireCheck)
2539  m_autoexpireCheck->SetEnabled(isScheduled);
2540 }
2541 
2543 {
2544  if (!item || !m_rule)
2545  return;
2546 
2547  m_rule->m_maxEpisodes = item->GetData().toInt();
2548 
2549  if (m_maxbehaviourList)
2551 }
2552 
2554 {
2555  if (!m_rule)
2556  return;
2557 
2558  if (m_recgroupList->GetDataValue().toString() != "__NEW_GROUP__")
2559  return;
2560 
2561  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2562 
2563  QString label =
2564  QObject::tr("New Recording group name: ");
2565 
2566  auto *textDialog = new MythTextInputDialog(popupStack, label,
2567  static_cast<InputFilter>(FilterSymbols | FilterPunct));
2568 
2569  textDialog->SetReturnEvent(m_screen, "newrecgroup");
2570 
2571  if (textDialog->Create())
2572  popupStack->AddScreen(textDialog, false);
2573 }
2574 
2575 void StoreOptMixin::SetRecGroup(int recgroupID, QString recgroup)
2576 {
2577  if (!m_rule || recgroupID <= 0)
2578  return;
2579 
2580  if (m_recgroupList)
2581  {
2582  recgroup = recgroup.trimmed();
2583  if (recgroup.isEmpty())
2584  return;
2585 
2586  QString label = QObject::tr("Include in the \"%1\" recording group");
2587  auto *item = new MythUIButtonListItem(m_recgroupList, label.arg(recgroup),
2588  qVariantFromValue(recgroup));
2590 
2591  if (m_other && m_other->m_recgroupList)
2592  {
2594  label.arg(recgroup), qVariantFromValue(recgroupID));
2596  }
2597  }
2598 }
2599 
2600 int StoreOptMixin::CreateRecordingGroup(const QString& groupName)
2601 {
2602  int groupID = -1;
2603  MSqlQuery query(MSqlQuery::InitCon());
2604 
2605  query.prepare("INSERT INTO recgroups SET recgroup = :NAME, "
2606  "displayname = :DISPLAYNAME");
2607  query.bindValue(":NAME", groupName);
2608  query.bindValue(":DISPLAYNAME", groupName);
2609 
2610  if (query.exec())
2611  groupID = query.lastInsertId().toInt();
2612 
2613  if (groupID <= 0)
2614  LOG(VB_GENERAL, LOG_ERR, QString("Could not create recording group (%1). "
2615  "Does it already exist?").arg(groupName));
2616 
2617  return groupID;
2618 }
2619 
2621 
2627 void PostProcMixin::Create(bool *err)
2628 {
2629  if (!m_rule)
2630  return;
2631 
2632  if (m_other && !m_other->m_commflagCheck)
2633  UIUtilE::Assign(m_screen, m_commflagCheck, "autocommflag", err);
2634  else
2635  UIUtilW::Assign(m_screen, m_commflagCheck, "autocommflag");
2636 
2637  if (m_other && !m_other->m_transcodeCheck)
2638  UIUtilE::Assign(m_screen, m_transcodeCheck, "autotranscode", err);
2639  else
2640  UIUtilW::Assign(m_screen, m_transcodeCheck, "autotranscode");
2641 
2643  UIUtilE::Assign(m_screen, m_transcodeprofileList, "transcodeprofile", err);
2644  else
2645  UIUtilW::Assign(m_screen, m_transcodeprofileList, "transcodeprofile");
2646 
2647  if (m_other && !m_other->m_userjob1Check)
2648  UIUtilE::Assign(m_screen, m_userjob1Check, "userjob1", err);
2649  else
2651 
2652  if (m_other && !m_other->m_userjob2Check)
2653  UIUtilE::Assign(m_screen, m_userjob2Check, "userjob2", err);
2654  else
2656 
2657  if (m_other && !m_other->m_userjob3Check)
2658  UIUtilE::Assign(m_screen, m_userjob3Check, "userjob3", err);
2659  else
2661 
2662  if (m_other && !m_other->m_userjob4Check)
2663  UIUtilE::Assign(m_screen, m_userjob4Check, "userjob4", err);
2664  else
2666 
2667  UIUtilW::Assign(m_screen, m_metadataLookupCheck, "metadatalookup");
2668 }
2669 
2671 {
2672  if (!m_rule)
2673  return;
2674 
2675  // Auto-commflag
2676  if (m_commflagCheck)
2677  {
2679  }
2680 
2681  // Auto-transcode
2682  if (m_transcodeCheck)
2683  {
2685  }
2686 
2687  // Transcode Method
2689  {
2690  if (!m_loaded)
2691  {
2692  QMap<int, QString> profiles = RecordingProfile::GetTranscodingProfiles();
2693  QMap<int, QString>::iterator it;
2694  for (it = profiles.begin(); it != profiles.end(); ++it)
2695  {
2697  qVariantFromValue(it.key()));
2698  }
2699  }
2701  }
2702 
2703  // User Job #1
2704  if (m_userjob1Check)
2705  {
2706  if (!m_loaded)
2707  {
2708  MythUIText *userjob1Text = nullptr;
2709  UIUtilW::Assign(m_screen, userjob1Text, "userjob1text");
2710  if (userjob1Text)
2711  userjob1Text->SetText(QObject::tr("Run '%1'")
2712  .arg(gCoreContext->GetSetting("UserJobDesc1", "User Job 1")));
2713  }
2715  }
2716 
2717  // User Job #2
2718  if (m_userjob2Check)
2719  {
2720  if (!m_loaded)
2721  {
2722  MythUIText *userjob2Text = nullptr;
2723  UIUtilW::Assign(m_screen, userjob2Text, "userjob2text");
2724  if (userjob2Text)
2725  userjob2Text->SetText(QObject::tr("Run '%1'")
2726  .arg(gCoreContext->GetSetting("UserJobDesc2", "User Job 2")));
2727  }
2729  }
2730 
2731  // User Job #3
2732  if (m_userjob3Check)
2733  {
2734  if (!m_loaded)
2735  {
2736  MythUIText *userjob3Text = nullptr;
2737  UIUtilW::Assign(m_screen, userjob3Text, "userjob3text");
2738  if (userjob3Text)
2739  userjob3Text->SetText(QObject::tr("Run '%1'")
2740  .arg(gCoreContext->GetSetting("UserJobDesc3", "User Job 3")));
2741  }
2743  }
2744 
2745  // User Job #4
2746  if (m_userjob4Check)
2747  {
2748  if (!m_loaded)
2749  {
2750  MythUIText *userjob4Text = nullptr;
2751  UIUtilW::Assign(m_screen, userjob4Text, "userjob4text");
2752  if (userjob4Text)
2753  userjob4Text->SetText(QObject::tr("Run '%1'")
2754  .arg(gCoreContext->GetSetting("UserJobDesc4", "User Job 4")));
2755  }
2757  }
2758 
2759  // Auto Metadata Lookup
2761  {
2763  }
2764 
2765  m_loaded = true;
2766 
2767  RuleChanged();
2768 }
2769 
2771 {
2772  if (!m_rule)
2773  return;
2774 
2775  if (m_commflagCheck)
2777  if (m_transcodeCheck)
2781  if (m_userjob1Check)
2783  if (m_userjob2Check)
2785  if (m_userjob3Check)
2787  if (m_userjob4Check)
2792 }
2793 
2795 {
2796  if (!m_rule)
2797  return;
2798 
2799  bool isScheduled = (m_rule->m_type != kNotRecording &&
2800  m_rule->m_type != kDontRecord);
2801 
2802  if (m_commflagCheck)
2803  m_commflagCheck->SetEnabled(isScheduled);
2804  if (m_transcodeCheck)
2805  m_transcodeCheck->SetEnabled(isScheduled);
2807  m_transcodeprofileList->SetEnabled(isScheduled &&
2809  if (m_userjob1Check)
2810  m_userjob1Check->SetEnabled(isScheduled);
2811  if (m_userjob2Check)
2812  m_userjob2Check->SetEnabled(isScheduled);
2813  if (m_userjob3Check)
2814  m_userjob3Check->SetEnabled(isScheduled);
2815  if (m_userjob4Check)
2816  m_userjob4Check->SetEnabled(isScheduled);
2818  m_metadataLookupCheck->SetEnabled(isScheduled);
2819 }
2820 
2822 {
2823  if (!m_rule)
2824  return;
2825 
2826  m_rule->m_autoTranscode = enable;
2827 
2830 }
QString m_subtitle
Definition: recordingrule.h:81
MetadataFactory * m_metadataFactory
MythScreenType * m_screen
void Create(bool *err)
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:781
void Save(void) override
MythUICheckBox * m_commflagCheck
bool m_isInactive
Recording rule is enabled?
Definition: recordingrule.h:76
void MaxEpisodesChanged(MythUIButtonListItem *)
static QString fs3(QT_TRANSLATE_NOOP("SchedFilterEditor", "Prime time"))
MythScreenStack * GetScreenStack() const
ScheduleEditor(MythScreenStack *parent, RecordingInfo *recinfo, TV *player=nullptr)
Select post-processing options.
void ruleDeleted(int ruleId)
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
void showUpcomingByTitle(void)
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:862
void Save(void) override
static QString fs6(QT_TRANSLATE_NOOP("SchedFilterEditor", "This episode"))
ArtworkList GetArtwork(VideoArtworkType type) const
MythUICheckBox * m_ruleactiveCheck
void RuleChanged(void)
void DupMethodChanged(MythUIButtonListItem *)
void SetAutomatic(bool autom)
#define ENUM_TO_QVARIANT(a)
MythUISpinBox * m_endoffsetSpin
bool StartEmbedding(const QRect &)
Definition: tv_play.cpp:8451
virtual void ToMap(InfoMap &progMap, bool showrerecord=false, uint star_range=10) const
Converts ProgramInfo into QString QHash containing each field in ProgramInfo converted into localized...
QString toDescription(RecordingType rectype)
Converts "rectype" into a human readable description.
bool LoadByProgram(const ProgramInfo *proginfo)
MythUIButton * m_localFanartButton
Dialog asking for user confirmation.
Select schedule filters.
static void ToggleSelected(MythUIButtonListItem *item)
bool Create(void) override
void LosingFocus()
void SetEnabled(bool enable)
Select artwork and inetref for recordings.
bool Delete(bool sendSig=true)
void TranscodeChanged(bool enable)
RecordingRule * m_recordingRule
MythScreenType * m_screen
MythUIButtonList * m_filtersList
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
void showUpcomingByRule(void)
All purpose text widget, displays a text string.
Definition: mythuitext.h:28
static QString fs8(QT_TRANSLATE_NOOP("SchedFilterEditor", "This time"))
MetadataType
void Load(void) override
virtual void ShowUpcoming(void) const
Show the upcoming recordings for this title.
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
ArtworkMap m_artworkMap
MythUISpinBox * m_prioritySpin
PostProcEditor(MythScreenStack *parent, ScheduleEditor &editor, RecordingRule &rule, RecordingInfo *recinfo)
void ToMap(InfoMap &infoMap) const
void templateLoaded(void)
static void FindImagePopup(const QString &prefix, const QString &prefixAlt, QObject &inst, const QString &returnEvent)
void SetData(QVariant data)
void MaxEpisodesChanged(MythUIButtonListItem *)
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
MythUIButtonList * m_playgroupList
void TranscodeChanged(bool enable)
LookupType GuessLookupType(ProgramInfo *pginfo)
Basic menu dialog, message and a list of options.
void SetRule(RecordingRule *rule)
void Create(bool *err)
VideoArtworkType
static QString fs9(QT_TRANSLATE_NOOP("SchedFilterEditor", "This day and time"))
MythUICheckBox * m_userjob4Check
MythUIButton * m_filtersButton
QString m_storageGroup
void customEvent(QEvent *event) override
static QStringList getRecordingsGroups(void)
bool SetArtwork(const QString &inetref, uint season, const QString &host, const QString &coverart, const QString &fanart, const QString &banner)
QString m_station
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:135
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:34
static void ToggleSelected(MythUIButtonListItem *item)
MythScreenStack * GetStack(const QString &stackname)
static QString fs4(QT_TRANSLATE_NOOP("SchedFilterEditor", "Commercial free"))
int m_recordID
Unique Recording Rule ID.
Definition: recordingrule.h:72
RecordingInfo * m_recInfo
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void SetValue(int val) override
Definition: mythuispinbox.h:26
RecordingType m_type
MythScreenStack * GetMainStack()
MythUIButton * m_schedOptButton
virtual void ShowDetails(void) const
Show the Program Details screen.
void showTemplateMenu(void)
SchedEditChild * m_child
RecordingDupMethodType m_dupMethod
void ShowSchedInfo(void)
MythUIButtonListItem * GetItemAt(int pos) const
Select schedule options.
static QString fs7(QT_TRANSLATE_NOOP("SchedFilterEditor", "This series"))
static QString fs2(QT_TRANSLATE_NOOP("SchedFilterEditor", "First showing"))
void OnImageSearchListSelection(const ArtworkInfo &info, VideoArtworkType type)
void SetRule(RecordingRule *rule)
SchedEditChild(MythScreenStack *parent, const QString &name, ScheduleEditor &editor, RecordingRule &rule, RecordingInfo *recinfo)
MythUITextEdit * m_inetrefEdit
void DeleteRule(void)
bool Create(void) override
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
Mixin for schedule options.
static QString fs10(QT_TRANSLATE_NOOP("SchedFilterEditor", "This channel"))
void BuildFocusList(void)
void Load(void) override
QList< ArtworkInfo > ArtworkList
static Type kEventType
Definition: mythdialogbox.h:50
RecordingRule * m_recordingRule
MetadataLookup * CreateLookup(MetadataType mtype)
MythUICheckBox * m_metadataLookupCheck
int GetIntValue(void) const override
Definition: mythuispinbox.h:33
MythUIImage * m_fanart
uint GetSeason() const
RecordingDupMethodType
QVariant value(int i) const
Definition: mythdbcon.h:198
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
void MaxEpisodesChanged(MythUIButtonListItem *)
virtual void Close()
MythUIButton * m_cancelButton
void setCheckable(bool flag)
MythScreenType * m_screen
MythUIButton * m_onlineFanartButton
bool Save(bool sendSig=true)
uint GetEpisode() const
Holds information on recordings and videos.
Definition: programinfo.h:66
void SetRange(int low, int high, int step, uint pageMultiple=5)
Set the lower and upper bounds of the spinbox, the interval and page amount.
RecordingRule * m_rule
void OnArtworkSearchDone(MetadataLookup *lookup)
bool GetBooleanCheckState(void) const
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Select storage options.
void toMap(InfoMap &map)
MythUIButton * m_metadataButton
MythUIButton * m_inetrefClear
void Load(void) override
MythUICheckBox * m_transcodeCheck
This class is used as a container for messages.
Definition: mythevent.h:16
void DupMethodChanged(MythUIButtonListItem *)
MythUIButton * m_saveButton
RecordingRule * m_rule
virtual void ShowGuide(void) const
Show the program guide.
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
virtual void ShowPrevious(void) const
Show the previous recordings for this recording rule.
MythUIButtonList * m_storagegroupList
static void FilterChanged(MythUIButtonListItem *)
bool Create(void) override
void ruleSaved(int ruleId)
QVariant lastInsertId()
Return the id of the last inserted row.
Definition: mythdbcon.cpp:886
static QString fs1(QT_TRANSLATE_NOOP("SchedFilterEditor", "Identifiable episode"))
Mixin for Filters.
MythUIButton * m_filtersButton
MythUIImage * m_coverart
bool Create(void) override
Construct a recording schedule.
bool m_autoMetadataLookup
QString GetSetting(const QString &key, const QString &defaultval="")
void RuleChanged(void)
MythUICheckBox * m_autoexpireCheck
void addDownloads(MetadataLookup *lookup)
addLookup: Add lookup to bottom of the queue MetadataDownload::m_downloadList takes ownership of the ...
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
QString m_playGroup
void Create(bool *err)
MythUIButtonList * m_inputList
MythUIButton * m_backButton
static QString fs5(QT_TRANSLATE_NOOP("SchedFilterEditor", "High definition"))
void ShowPostProc(void)
void customEvent(QEvent *event) override
StoreOptEditor(MythScreenStack *parent, ScheduleEditor &editor, RecordingRule &rule, RecordingInfo *recinfo)
MythUIButton * m_schedInfoButton
virtual void SetTextFromMap(const InfoMap &infoMap)
Control TV playback.
Definition: tv_play.h:279
QString GetMasterHostName(void)
RecordingRule * m_rule
QVariant GetDataValue() const
MythUIButton * m_saveButton
bool Queue(const MythNotification &notification)
Queue a notification Queue() is thread-safe and can be called from anywhere.
bool LoadTemplate(const QString &category, const QString &categoryType="Default")
virtual bool CreateEditChild(const QString &xmlfile, const QString &winname, bool isTemplate)
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
Mixin for storage options.
void SetRule(RecordingRule *rule)
static vector< uint > GetSchedInputList(void)
bool Create(void) override
void Closing(void)
uint GetSeason(void) const
Definition: programinfo.h:358
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:534
void FindNetArt(VideoArtworkType type)
void Save(void) override
void CreateBusyDialog(const QString &title)
MythUIBusyDialog * m_busyPopup
Internal representation of a recording rule, mirrors the record table.
Definition: recordingrule.h:32
void SetRecGroup(int recgroupID, QString recgroup)
QString GetInetref() const
bool Create(void) override
void ShowSchedOpt(void)
void ShowFilters(void)
FilterOptMixin * m_other
void ShowMetadataOptions(void)
QString m_seriesid
Definition: recordingrule.h:93
void Save(void) override
MythUIButton * m_localBannerButton
MythUIButton * m_previewButton
CheckState state() const
RecordingRule * m_rule
MythUIButtonList * m_newrepeatList
RecordingInfo * m_recInfo
void PromptForRecGroup(void)
MythUIButton * m_postProcButton
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
RecordingDupInType m_dupIn
void ChildClosing(void)
void SetText(const QString &text, bool moveCursor=true)
QVariant GetData() const
MythUIType * GetFocusWidget(void) const
QString m_inetref
Definition: recordingrule.h:96
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
MythMainWindow * GetMythMainWindow(void)
void Create(bool *err)
static QStringList GetSupportedImageExtensionFilter()
MythScreenType * m_screen
MythUIImage * m_banner
MetadataDownload * m_imageLookup
uint GetYearOfInitialRelease(void) const
Definition: programinfo.h:415
void PromptForRecGroup(void)
MythUISpinBox * m_startoffsetSpin
void Load(void) override
MythUISpinBox * m_seasonSpin
MythUIButton * m_onlineBannerButton
MythUIButtonList * m_transcodeprofileList
static QString fs11(QT_TRANSLATE_NOOP("SchedFilterEditor", "No episodes"))
Dialog prompting the user to enter a text string.
void TranscodeChanged(bool enable)
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:806
void DupMethodChanged(MythUIButtonListItem *item)
MythUICheckBox * m_userjob3Check
bool keyPressEvent(QKeyEvent *) override
Key event handler.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QMap< VideoArtworkType, ArtworkInfo > DownloadMap
static Type kEventType
bool IsLoaded() const
Definition: recordingrule.h:57
void QueryComplete(MetadataLookup *lookup)
QString m_title
Definition: recordingrule.h:79
void RuleChanged(void)
virtual void PopScreen(MythScreenType *screen=nullptr, bool allowFade=true, bool deleteScreen=true)
void ShowStoreOpt(void)
MythUIButton * m_onlineCoverartButton
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
SchedOptMixin(MythScreenType &screen, RecordingRule *rule, SchedOptMixin *other=nullptr)
void showMenu(void)
MythUICheckBox * m_userjob2Check
void Lookup(ProgramInfo *pginfo, bool automatic=true, bool getimages=true, bool allowgeneric=false)
MythUIButtonList * m_maxbehaviourList
QString m_recProfile
uint GetRecordingRuleID(void) const
Definition: programinfo.h:441
void SetRule(RecordingRule *rule)
void UseTempTable(bool usetemp, const QString &table="record_tmp")
MythUIButton * m_previewButton
QStringList m_descriptions
MythScreenStack * m_popupStack
bool CanSetArtwork(void)
static QStringList GetNames(void)
Definition: playgroup.cpp:206
SchedFilterEditor(MythScreenStack *parent, ScheduleEditor &editor, RecordingRule &rule, RecordingInfo *recinfo)
void SetCheckState(MythUIStateType::StateType state)
MythUIButtonList * m_dupscopeList
bool Load(bool asTemplate=false)
Load a single rule from the recorded table.
unsigned m_filter
QString generate_file_url(const QString &storage_group, const QString &host, const QString &path)
Definition: videoutils.h:65
void Close(void) override
QString m_category
Definition: recordingrule.h:86
MythUICheckBox * m_userjob1Check
void Load(void) override=0
void SetItemCurrent(MythUIButtonListItem *item)
MythUIButton * m_queryButton
DownloadMap GetDownloads() const
void Load(void) override
MetadataImageDownload * m_imageDownload
MythUIButton * m_localCoverartButton
static QStringList GetTemplateNames(void)
void PromptForRecGroup(void)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:602
MythUIButtonList * m_dupmethodList
QMultiMap< VideoArtworkType, ArtworkInfo > ArtworkMap
Screen in which all other widgets are contained and rendered.
void Save(void) override
MythUISpinBox * m_maxepSpin
ScheduleEditor * m_editor
MythUIButtonList * m_activeFiltersList
void addLookup(MetadataLookup *lookup)
addLookup: Add lookup to bottom of the queue MetadataDownload::m_lookupList takes ownership of the gi...
MythUISpinBox * m_episodeSpin
virtual void Save(void)=0
LookupType
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:37
void ShowNextView(void)
MythUIButton * m_storeOptButton
static void * RunScheduleEditor(ProgramInfo *proginfo, void *player=nullptr)
Callback.
StoreOptMixin * m_other
static QMap< int, QString > GetTranscodingProfiles()
void SetCanTakeFocus(bool set=true)
Set whether this widget can take focus.
Definition: mythuitype.cpp:344
void ShowPreviousView(void)
void OnSearchListSelection(const RefCountHandler< MetadataLookup > &lookup)
MythUIButtonList * m_recprofileList
CategoryType GetCategoryType(void) const
Definition: programinfo.h:430
static QString fs0(QT_TRANSLATE_NOOP("SchedFilterEditor", "New episode"))
MetadataOptions(MythScreenStack *parent, ScheduleEditor &editor, RecordingRule &rule, RecordingInfo *recinfo)
PostProcMixin * m_other
void setChecked(CheckState state)
static int CreateRecordingGroup(const QString &groupName)
SchedOptMixin * m_other
MythUIButtonList * m_recgroupList
void ShowPreview(void)
RecSearchType m_searchType
Mixin for post processing.
ArtworkMap GetArtwork(const QString &inetref, uint season, bool strict)
QString GetText(void) const
MythNotificationCenter * GetNotificationCenter(void)
MythUIButtonListItem * GetItemCurrent() const
void SetValueByData(const QVariant &data)
void LoadTemplate(const QString &name)
MythUIButtonList * m_rulesList
uint GetEpisode(void) const
Definition: programinfo.h:359
void Close(void) override
SchedOptEditor(MythScreenStack *parent, ScheduleEditor &editor, RecordingRule &rule, RecordingInfo *recinfo)
void SetTextFromMaps(void)
bool Create(void) override
void RuleChanged(void)
static QString GetDisplayName(uint inputid)
Definition: cardutil.cpp:1729
void customEvent(QEvent *event) override
void HandleDownloadedImages(MetadataLookup *lookup)