MythTV  master
playbackbox.cpp
Go to the documentation of this file.
1 #include "playbackbox.h"
2 
3 // C++
4 #include <algorithm>
5 #include <array>
6 
7 // QT
8 #include <QCoreApplication>
9 #include <QDateTime>
10 #include <QLocale>
11 #include <QTimer>
12 #include <QMap>
13 
14 // MythTV
15 #ifdef _MSC_VER
16 # include "libmythbase/compat.h" // for random
17 #endif
20 #include "libmythbase/mythdate.h"
21 #include "libmythbase/mythdb.h"
22 #include "libmythbase/mythdbcon.h"
23 #include "libmythbase/mythevent.h" // for MythEvent, etc
25 #include "libmythbase/mythrandom.h"
27 #include "libmythbase/programtypes.h" // for AudioProps, SubtitleTypes, etc
29 #include "libmythbase/stringutil.h"
31 #include "libmythtv/playgroup.h"
35 #include "libmythtv/tv.h"
36 #include "libmythtv/tv_actions.h" // for ACTION_LISTRECORDEDEPISODES, etc
38 #include "libmythui/mythmainwindow.h" // for GetMythMainWindow, etc
39 #include "libmythui/mythnotificationcenter.h" // for ShowNotificationError, etc
41 #include "libmythui/mythscreenstack.h" // for MythScreenStack
42 #include "libmythui/mythuiactions.h" // for ACTION_1
43 #include "libmythui/mythuibutton.h"
46 #include "libmythui/mythuiimage.h"
50 #include "libmythui/mythuitext.h"
52 
53 // MythFrontend
54 #include "playbackboxlistitem.h"
55 
56 #define LOC QString("PlaybackBox: ")
57 #define LOC_WARN QString("PlaybackBox Warning: ")
58 #define LOC_ERR QString("PlaybackBox Error: ")
59 
60 static const QString sLocation = "Playback Box";
61 
62 static int comp_programid(const ProgramInfo *a, const ProgramInfo *b)
63 {
64  if (a->GetProgramID() == b->GetProgramID())
65  return (a->GetRecordingStartTime() <
66  b->GetRecordingStartTime() ? 1 : -1);
67  return (a->GetProgramID() < b->GetProgramID() ? 1 : -1);
68 }
69 
70 static int comp_programid_rev(const ProgramInfo *a, const ProgramInfo *b)
71 {
72  if (a->GetProgramID() == b->GetProgramID())
73  return (a->GetRecordingStartTime() >
74  b->GetRecordingStartTime() ? 1 : -1);
75  return (a->GetProgramID() > b->GetProgramID() ? 1 : -1);
76 }
77 
78 static int comp_originalAirDate(const ProgramInfo *a, const ProgramInfo *b)
79 {
80  QDate dt1 = (a->GetOriginalAirDate().isValid()) ?
81  a->GetOriginalAirDate() : a->GetScheduledStartTime().date();
82  QDate dt2 = (b->GetOriginalAirDate().isValid()) ?
83  b->GetOriginalAirDate() : b->GetScheduledStartTime().date();
84 
85  if (dt1 == dt2)
86  return (a->GetRecordingStartTime() <
87  b->GetRecordingStartTime() ? 1 : -1);
88  return (dt1 < dt2 ? 1 : -1);
89 }
90 
91 static int comp_originalAirDate_rev(const ProgramInfo *a, const ProgramInfo *b)
92 {
93  QDate dt1 = (a->GetOriginalAirDate().isValid()) ?
94  a->GetOriginalAirDate() : a->GetScheduledStartTime().date();
95  QDate dt2 = (b->GetOriginalAirDate().isValid()) ?
96  b->GetOriginalAirDate() : b->GetScheduledStartTime().date();
97 
98  if (dt1 == dt2)
99  return (a->GetRecordingStartTime() >
100  b->GetRecordingStartTime() ? 1 : -1);
101  return (dt1 > dt2 ? 1 : -1);
102 }
103 
104 static int comp_recpriority2(const ProgramInfo *a, const ProgramInfo *b)
105 {
107  return (a->GetRecordingStartTime() <
108  b->GetRecordingStartTime() ? 1 : -1);
109  return (a->GetRecordingPriority2() <
110  b->GetRecordingPriority2() ? 1 : -1);
111 }
112 
113 static int comp_recordDate(const ProgramInfo *a, const ProgramInfo *b)
114 {
115  if (a->GetScheduledStartTime().date() == b->GetScheduledStartTime().date())
116  return (a->GetRecordingStartTime() <
117  b->GetRecordingStartTime() ? 1 : -1);
118  return (a->GetScheduledStartTime().date() <
119  b->GetScheduledStartTime().date() ? 1 : -1);
120 }
121 
122 static int comp_recordDate_rev(const ProgramInfo *a, const ProgramInfo *b)
123 {
124  if (a->GetScheduledStartTime().date() == b->GetScheduledStartTime().date())
125  return (a->GetRecordingStartTime() >
126  b->GetRecordingStartTime() ? 1 : -1);
127  return (a->GetScheduledStartTime().date() >
128  b->GetScheduledStartTime().date() ? 1 : -1);
129 }
130 
131 static int comp_season(const ProgramInfo *a, const ProgramInfo *b)
132 {
133  if (a->GetSeason() == 0 || b->GetSeason() == 0)
134  return comp_originalAirDate(a, b);
135  if (a->GetSeason() != b->GetSeason())
136  return (a->GetSeason() < b->GetSeason() ? 1 : -1);
137  if (a->GetEpisode() == 0 && b->GetEpisode() == 0)
138  return comp_originalAirDate(a, b);
139  return (a->GetEpisode() < b->GetEpisode() ? 1 : -1);
140 }
141 
142 static int comp_season_rev(const ProgramInfo *a, const ProgramInfo *b)
143 {
144  if (a->GetSeason() == 0 || b->GetSeason() == 0)
145  return comp_originalAirDate_rev(a, b);
146  if (a->GetSeason() != b->GetSeason())
147  return (a->GetSeason() > b->GetSeason() ? 1 : -1);
148  if (a->GetEpisode() == 0 && b->GetEpisode() == 0)
149  return comp_originalAirDate_rev(a, b);
150  return (a->GetEpisode() > b->GetEpisode() ? 1 : -1);
151 }
152 
154  const ProgramInfo *a, const ProgramInfo *b)
155 {
156  return comp_programid(a, b) < 0;
157 }
158 
160  const ProgramInfo *a, const ProgramInfo *b)
161 {
162  return comp_programid_rev(a, b) < 0;
163 }
164 
166  const ProgramInfo *a, const ProgramInfo *b)
167 {
168  return comp_originalAirDate(a, b) < 0;
169 }
170 
172  const ProgramInfo *a, const ProgramInfo *b)
173 {
174  return comp_originalAirDate_rev(a, b) < 0;
175 }
176 
178  const ProgramInfo *a, const ProgramInfo *b)
179 {
180  return comp_recpriority2(a, b) < 0;
181 }
182 
184  const ProgramInfo *a, const ProgramInfo *b)
185 {
186  return comp_recordDate(a, b) < 0;
187 }
188 
190  const ProgramInfo *a, const ProgramInfo *b)
191 {
192  return comp_recordDate_rev(a, b) < 0;
193 }
194 
196  const ProgramInfo *a, const ProgramInfo *b)
197 {
198  return comp_season(a, b) < 0;
199 }
200 
202  const ProgramInfo *a, const ProgramInfo *b)
203 {
204  return comp_season_rev(a, b) < 0;
205 }
206 
207 static const std::array<const uint,3> s_artDelay
209 
211  PlaybackBox::ViewMask toggle)
212 {
213  // can only toggle a single bit at a time
214  if ((mask & toggle))
215  return (PlaybackBox::ViewMask)(mask & ~toggle);
216  return (PlaybackBox::ViewMask)(mask | toggle);
217 }
218 
219 static QString construct_sort_title(
220  QString title, const QString& sortTitle, PlaybackBox::ViewMask viewmask,
221  PlaybackBox::ViewTitleSort sortType, int recpriority)
222 {
223  if (title.isEmpty())
224  return title;
225 
226  QString sTitle = sortTitle.isEmpty()
227  ? title : sortTitle + " - " + title;
228 
229  if (viewmask == PlaybackBox::VIEW_TITLES &&
231  {
232  // Also incorporate recpriority (reverse numeric sort). In
233  // case different episodes of a recording schedule somehow
234  // have different recpriority values (e.g., manual fiddling
235  // with database), the title will appear once for each
236  // distinct recpriority value among its episodes.
237  //
238  // Deal with QMap sorting. Positive recpriority values have a
239  // '+' prefix (QMap alphabetically sorts before '-'). Positive
240  // recpriority values are "inverted" by subtracting them from
241  // 1000, so that high recpriorities are sorted first (QMap
242  // alphabetically). For example:
243  //
244  // recpriority => sort key
245  // 95 +905
246  // 90 +910
247  // 89 +911
248  // 1 +999
249  // 0 -000
250  // -5 -005
251  // -10 -010
252  // -99 -099
253 
254  QString sortprefix;
255  if (recpriority > 0)
256  sortprefix = QString("+%1").arg(1000 - recpriority, 3, 10, QChar('0'));
257  else
258  sortprefix = QString("-%1").arg(-recpriority, 3, 10, QChar('0'));
259 
260  sTitle = sortprefix + '-' + sTitle;
261  }
262  return sTitle;
263 }
264 
265 static QString extract_main_state(const ProgramInfo &pginfo, const TV *player)
266 {
267  QString state("normal");
268  if (pginfo.GetFilesize() == 0)
269  state = "error";
270  else if (pginfo.GetRecordingStatus() == RecStatus::Recording ||
273  state = "running";
274 
275  if (((pginfo.GetRecordingStatus() != RecStatus::Recording) &&
276  (pginfo.GetAvailableStatus() != asAvailable) &&
277  (pginfo.GetAvailableStatus() != asNotYetAvailable)) ||
278  (player && player->IsSameProgram(&pginfo)))
279  {
280  state = "disabled";
281  }
282 
283  if ((state == "normal" || state == "running") &&
284  pginfo.GetVideoProperties() & VID_DAMAGED)
285  {
286  state = "warning";
287  }
288 
289  return state;
290 }
291 
293 {
294  QString job = "default";
295 
296  if (pginfo.GetRecordingStatus() == RecStatus::Recording ||
299  job = "recording";
301  JOB_TRANSCODE, pginfo.GetChanID(),
302  pginfo.GetRecordingStartTime()))
303  job = "transcoding";
305  JOB_COMMFLAG, pginfo.GetChanID(),
306  pginfo.GetRecordingStartTime()))
307  job = "commflagging";
308 
309  return job;
310 }
311 
313 {
314  // commflagged can be yes, no or processing
316  pginfo.GetRecordingStartTime()))
317  return "running";
319  pginfo.GetRecordingStartTime()))
320  return "queued";
321 
322  return ((pginfo.GetProgramFlags() & FL_COMMFLAG) ? "yes" : "no");
323 }
324 
325 
326 static QString extract_subtitle(
327  const ProgramInfo &pginfo, const QString &groupname)
328 {
329  QString subtitle;
330  if (groupname != pginfo.GetTitle().toLower())
331  {
332  subtitle = pginfo.toString(ProgramInfo::kTitleSubtitle, " - ");
333  }
334  else
335  {
336  subtitle = pginfo.GetSubtitle();
337  if (subtitle.trimmed().isEmpty())
338  subtitle = pginfo.GetTitle();
339  }
340  return subtitle;
341 }
342 
343 static void push_onto_del(QStringList &list, const ProgramInfo &pginfo)
344 {
345  list.clear();
346  list.push_back(QString::number(pginfo.GetRecordingID()));
347  list.push_back(QString() /* force Delete */);
348  list.push_back(QString()); /* forget history */
349 }
350 
351 static bool extract_one_del(QStringList &list, uint &recordingID)
352 {
353  if (list.size() < 3)
354  {
355  list.clear();
356  return false;
357  }
358 
359  recordingID = list[0].toUInt();
360 
361  list.pop_front();
362  list.pop_front();
363  list.pop_front();
364 
365  if (recordingID == 0U) {
366  LOG(VB_GENERAL, LOG_ERR, LOC + "extract_one_del() invalid entry");
367  return false;
368  }
369  return true;
370 }
371 
372 void * PlaybackBox::RunPlaybackBox(void * player, bool showTV)
373 {
375 
376  auto *pbb = new PlaybackBox(mainStack,"playbackbox", (TV *)player, showTV);
377 
378  if (pbb->Create())
379  mainStack->AddScreen(pbb);
380  else
381  delete pbb;
382 
383  return nullptr;
384 }
385 
386 PlaybackBox::PlaybackBox(MythScreenStack *parent, const QString& name,
387  TV *player, bool /*showTV*/)
388  : ScheduleCommon(parent, name),
389  // Recording Group settings
390  m_groupDisplayName(ProgramInfo::i18n("All Programs")),
391  m_recGroup("All Programs"),
392  m_watchGroupName(tr("Watch List")),
393  m_watchGroupLabel(m_watchGroupName.toLower()),
394 
395  // Other state
396  m_programInfoCache(this),
397  // Other
398  m_helper(this)
399 {
400  for (size_t i = 0; i < kNumArtImages; i++)
401  {
402  m_artImage[i] = nullptr;
403  m_artTimer[i] = new QTimer(this);
404  m_artTimer[i]->setSingleShot(true);
405  }
406 
407  m_recGroup = gCoreContext->GetSetting("DisplayRecGroup",
408  "All Programs");
409  int pbOrder = gCoreContext->GetNumSetting("PlayBoxOrdering", 3);
410  // Split out sort order modes, wacky order for backward compatibility
411  m_listOrder = (pbOrder >> 1) ^ (m_allOrder = pbOrder & 1);
412  m_watchListStart = gCoreContext->GetBoolSetting("PlaybackWLStart", false);
413 
414  m_watchListAutoExpire= gCoreContext->GetBoolSetting("PlaybackWLAutoExpire", false);
415  m_watchListMaxAge = gCoreContext->GetNumSetting("PlaybackWLMaxAge", 60);
417  std::chrono::days(2));
418 
419  bool displayCat = gCoreContext->GetBoolSetting("DisplayRecGroupIsCategory", false);
420 
422  "DisplayGroupDefaultViewMask",
424 
425  // Translate these external settings into mask values
426  if (gCoreContext->GetBoolSetting("PlaybackWatchList", true) &&
427  ((m_viewMask & VIEW_WATCHLIST) == 0))
428  {
430  gCoreContext->SaveSetting("DisplayGroupDefaultViewMask", (int)m_viewMask);
431  }
432  else if (! gCoreContext->GetBoolSetting("PlaybackWatchList", true) &&
433  ((m_viewMask & VIEW_WATCHLIST) != 0))
434  {
436  gCoreContext->SaveSetting("DisplayGroupDefaultViewMask", (int)m_viewMask);
437  }
438 
439  // This setting is deprecated in favour of viewmask, this just ensures the
440  // that it is converted over when upgrading from earlier versions
441  if (gCoreContext->GetBoolSetting("LiveTVInAllPrograms",false) &&
442  ((m_viewMask & VIEW_LIVETVGRP) == 0))
443  {
445  gCoreContext->SaveSetting("DisplayGroupDefaultViewMask", (int)m_viewMask);
446  }
447 
448  if (gCoreContext->GetBoolSetting("MasterBackendOverride", false))
450 
451  if (player)
452  {
453  m_player = player;
454  m_player->IncrRef();
455  QString tmp = m_player->GetRecordingGroup();
456  if (!tmp.isEmpty())
457  m_recGroup = tmp;
458  }
459 
460  // recording group stuff
461  m_recGroupIdx = -1;
462  m_recGroupType.clear();
464  (displayCat && m_recGroup != "All Programs") ? "category" : "recgroup";
466 
468 
469  m_alwaysShowWatchedProgress = gCoreContext->GetBoolSetting("AlwaysShowWatchedProgress", false);
470 
471  // misc setup
472  gCoreContext->addListener(this);
473 
474  m_popupStack = GetMythMainWindow()->GetStack("popup stack");
475 }
476 
478 {
481 
482  for (size_t i = 0; i < kNumArtImages; i++)
483  {
484  m_artTimer[i]->disconnect(this);
485  m_artTimer[i] = nullptr;
486  m_artImage[i] = nullptr;
487  }
488 
489  if (m_player)
490  {
492  m_player->DecrRef();
493  }
494 }
495 
497 {
498  if (!LoadWindowFromXML("recordings-ui.xml", "watchrecordings", this))
499  return false;
500 
501  m_recgroupList = dynamic_cast<MythUIButtonList *> (GetChild("recgroups"));
502  m_groupList = dynamic_cast<MythUIButtonList *> (GetChild("groups"));
503  m_recordingList = dynamic_cast<MythUIButtonList *> (GetChild("recordings"));
504 
505  m_noRecordingsText = dynamic_cast<MythUIText *> (GetChild("norecordings"));
506 
507  m_previewImage = dynamic_cast<MythUIImage *>(GetChild("preview"));
508  m_recordedProgress = dynamic_cast<MythUIProgressBar *>(GetChild("recordedprogressbar"));
509  m_watchedProgress = dynamic_cast<MythUIProgressBar *>(GetChild("watchedprogressbar"));
510  m_artImage[kArtworkFanart] = dynamic_cast<MythUIImage*>(GetChild("fanart"));
511  m_artImage[kArtworkBanner] = dynamic_cast<MythUIImage*>(GetChild("banner"));
512  m_artImage[kArtworkCoverart]= dynamic_cast<MythUIImage*>(GetChild("coverart"));
513 
514  if (!m_recordingList || !m_groupList)
515  {
516  LOG(VB_GENERAL, LOG_ERR, LOC +
517  "Theme is missing critical theme elements.");
518  return false;
519  }
520 
521  if (m_recgroupList)
522  {
523  if (gCoreContext->GetBoolSetting("RecGroupsFocusable", false))
524  {
527  }
528  else
529  {
531  }
532  }
533 
537  this, &PlaybackBox::SwitchList);
541  this, qOverload<>(&PlaybackBox::PlayFromAnyMark));
543  this, &PlaybackBox::ItemVisible);
545  this, &PlaybackBox::ItemLoaded);
546 
547  // connect up timers...
551 
552  BuildFocusList();
555 
556  if (m_player)
557  emit m_player->RequestEmbedding(true);
558  return true;
559 }
560 
562 {
565 }
566 
568 {
569  m_groupList->SetLCDTitles(tr("Groups"));
570  m_recordingList->SetLCDTitles(tr("Recordings"),
571  "titlesubtitle|shortdate|starttime");
572 
573  m_recordingList->SetSearchFields("titlesubtitle");
574 
575  if (gCoreContext->GetNumSetting("QueryInitialFilter", 0) == 1)
576  showGroupFilter();
577  else if (!m_player)
579  else
580  {
581  UpdateUILists();
582 
583  if ((m_titleList.size() <= 1) && (m_progsInDB > 0))
584  {
585  m_recGroup.clear();
586  showGroupFilter();
587  }
588  }
589 
590  if (!gCoreContext->GetBoolSetting("PlaybackBoxStartInTitle", false))
592 }
593 
595 {
596  if (GetFocusWidget() == m_groupList)
598  else if (GetFocusWidget() == m_recordingList)
600 }
601 
602 void PlaybackBox::displayRecGroup(const QString &newRecGroup)
603 {
604  m_groupSelected = true;
605 
606  QString password = getRecGroupPassword(newRecGroup);
607 
608  m_newRecGroup = newRecGroup;
609  if (m_curGroupPassword != password && !password.isEmpty())
610  {
611  MythScreenStack *popupStack =
612  GetMythMainWindow()->GetStack("popup stack");
613 
614  QString label = tr("Password for group '%1':").arg(newRecGroup);
615 
616  auto *pwd = new MythTextInputDialog(popupStack, label, FilterNone, true);
617 
618  connect(pwd, &MythTextInputDialog::haveResult,
620  connect(pwd, &MythScreenType::Exiting,
622 
623  m_passwordEntered = false;
624 
625  if (pwd->Create())
626  popupStack->AddScreen(pwd, false);
627 
628  return;
629  }
630 
631  setGroupFilter(newRecGroup);
632 }
633 
634 void PlaybackBox::checkPassword(const QString &password)
635 {
636  if (password == getRecGroupPassword(m_newRecGroup))
637  {
638  m_curGroupPassword = password;
639  m_passwordEntered = true;
641  }
642 }
643 
645 {
646  if (!m_passwordEntered &&
648  showGroupFilter();
649 }
650 
651 void PlaybackBox::updateGroupInfo(const QString &groupname,
652  const QString &grouplabel)
653 {
654  InfoMap infoMap;
655  QString desc;
656 
657  infoMap["group"] = m_groupDisplayName;
658  infoMap["title"] = grouplabel;
659  infoMap["show"] =
660  groupname.isEmpty() ? ProgramInfo::i18n("All Programs") : grouplabel;
661  int countInGroup = m_progLists[groupname].size();
662 
664  {
665  if (!groupname.isEmpty() && !m_progLists[groupname].empty())
666  {
667  ProgramInfo *pginfo = *m_progLists[groupname].begin();
668 
669  QString fn = m_helper.LocateArtwork(
670  pginfo->GetInetRef(), pginfo->GetSeason(), kArtworkFanart, nullptr, groupname);
671 
672  if (fn.isEmpty())
673  {
674  m_artTimer[kArtworkFanart]->stop();
675  m_artImage[kArtworkFanart]->Reset();
676  }
677  else if (m_artImage[kArtworkFanart]->GetFilename() != fn)
678  {
679  m_artImage[kArtworkFanart]->SetFilename(fn);
681  }
682  }
683  else
684  {
685  m_artImage[kArtworkFanart]->Reset();
686  }
687  }
688 
689 
690  if (countInGroup >= 1)
691  {
692  ProgramList group = m_progLists[groupname];
693  float groupSize = 0.0;
694 
695  for (auto *info : group)
696  {
697  if (info)
698  {
699  uint64_t filesize = info->GetFilesize();
700 // This query should be unnecessary if the ProgramInfo Updater is working
701 // if (filesize == 0 || info->GetRecordingStatus() == RecStatus::Recording)
702 // {
703 // filesize = info->QueryFilesize();
704 // info->SetFilesize(filesize);
705 // }
706  groupSize += filesize;
707  }
708  }
709 
710  desc = tr("There is/are %n recording(s) in this display "
711  "group, which consume(s) %1 GiB.", "", countInGroup)
712  .arg(groupSize / 1024.0F / 1024.0F / 1024.0F, 0, 'f', 2);
713  }
714  else
715  {
716  desc = tr("There is no recording in this display group.");
717  }
718 
719  infoMap["description"] = desc;
720  infoMap["rec_count"] = QString("%1").arg(countInGroup);
721 
723  SetTextFromMap(infoMap);
724  m_currentMap = infoMap;
725 
726  MythUIStateType *ratingState = dynamic_cast<MythUIStateType*>
727  (GetChild("ratingstate"));
728  if (ratingState)
729  ratingState->Reset();
730 
731  MythUIStateType *jobState = dynamic_cast<MythUIStateType*>
732  (GetChild("jobstate"));
733  if (jobState)
734  jobState->Reset();
735 
736  if (m_previewImage)
738 
740  m_artImage[kArtworkBanner]->Reset();
741 
743  m_artImage[kArtworkCoverart]->Reset();
744 
745  updateIcons();
746 }
747 
749  bool force_preview_reload)
750 {
751  if (!pginfo)
752  return;
753 
754  MythUIButtonListItem *item =
755  m_recordingList->GetItemByData(QVariant::fromValue(pginfo));
756 
757  if (item)
758  {
759  MythUIButtonListItem *sel_item =
761  UpdateUIListItem(item, item == sel_item, force_preview_reload);
762  }
763  else
764  {
765  LOG(VB_GENERAL, LOG_DEBUG, LOC +
766  QString("UpdateUIListItem called with a title unknown "
767  "to us in m_recordingList\n\t\t\t%1")
768  .arg(pginfo->toString(ProgramInfo::kTitleSubtitle)));
769  }
770 }
771 
772 static const std::array<const std::string,9> disp_flags
773 {
774  "playlist", "watched", "preserve",
775  "cutlist", "autoexpire", "editing",
776  "bookmark", "inuse", "transcoded"
777 };
778 
780 {
781  std::array<bool,disp_flags.size()> disp_flag_stat {};
782 
783  disp_flag_stat[0] = m_playList.contains(pginfo->GetRecordingID());
784  disp_flag_stat[1] = pginfo->IsWatched();
785  disp_flag_stat[2] = pginfo->IsPreserved();
786  disp_flag_stat[3] = pginfo->HasCutlist();
787  disp_flag_stat[4] = pginfo->IsAutoExpirable();
788  disp_flag_stat[5] = ((pginfo->GetProgramFlags() & FL_EDITING) != 0U);
789  disp_flag_stat[6] = pginfo->IsBookmarkSet();
790  disp_flag_stat[7] = pginfo->IsInUsePlaying();
791  disp_flag_stat[8] = ((pginfo->GetProgramFlags() & FL_TRANSCODED) != 0U);
792 
793  for (size_t i = 0; i < disp_flags.size(); ++i)
794  item->DisplayState(disp_flag_stat[i] ? "yes" : "no",
795  QString::fromStdString(disp_flags[i]));
796 }
797 
799  bool is_sel, bool force_preview_reload)
800 {
801  if (!item)
802  return;
803 
804  auto *pginfo = item->GetData().value<ProgramInfo *>();
805 
806  if (!pginfo)
807  return;
808 
809  QString state = extract_main_state(*pginfo, m_player);
810 
811  // Update the text, e.g. Title or subtitle may have been changed on another
812  // frontend
814  {
815  InfoMap infoMap;
816  pginfo->ToMap(infoMap);
817  item->SetTextFromMap(infoMap);
818 
819  QString groupname =
820  m_groupList->GetItemCurrent()->GetData().toString();
821 
822  QString tempSubTitle = extract_subtitle(*pginfo, groupname);
823 
824  if (groupname == pginfo->GetTitle().toLower())
825  {
826  item->SetText(tempSubTitle, "titlesubtitle");
827  // titlesubtitle will just have the subtitle, so put the full
828  // string in titlesubtitlefull, when a theme can then "depend" on.
829  item->SetText(pginfo->toString(ProgramInfo::kTitleSubtitle, " - "),
830  "titlesubtitlefull");
831  }
832  }
833 
834  // Recording and availability status
835  item->SetFontState(state);
836  item->DisplayState(state, "status");
837 
838  // Job status (recording, transcoding, flagging)
839  QString job = extract_job_state(*pginfo);
840  item->DisplayState(job, "jobstate");
841 
842  // Flagging status (queued, running, no, yes)
843  item->DisplayState(extract_commflag_state(*pginfo), "commflagged");
844 
845  SetItemIcons(item, pginfo);
846 
847  QString rating = QString::number(pginfo->GetStars(10));
848 
849  item->DisplayState(rating, "ratingstate");
850 
851  QString oldimgfile = item->GetImageFilename("preview");
852  if (oldimgfile.isEmpty() || force_preview_reload)
853  m_previewTokens.insert(m_helper.GetPreviewImage(*pginfo));
854 
855  if ((GetFocusWidget() == m_recordingList) && is_sel)
856  {
857  InfoMap infoMap;
858 
859  pginfo->CalculateProgress(pginfo->QueryLastPlayPos());
860 
861  pginfo->ToMap(infoMap);
862  infoMap["group"] = m_groupDisplayName;
864  SetTextFromMap(infoMap);
865  m_currentMap = infoMap;
866 
867  MythUIStateType *ratingState = dynamic_cast<MythUIStateType*>
868  (GetChild("ratingstate"));
869  if (ratingState)
870  ratingState->DisplayState(rating);
871 
872  MythUIStateType *jobState = dynamic_cast<MythUIStateType*>
873  (GetChild("jobstate"));
874  if (jobState)
875  jobState->DisplayState(job);
876 
877  if (m_previewImage)
878  {
879  m_previewImage->SetFilename(oldimgfile);
880  m_previewImage->Load(true, true);
881  }
882 
883  if (m_recordedProgress)
884  m_recordedProgress->Set(0, 100, pginfo->GetRecordedPercent());
885  if (m_watchedProgress)
886  m_watchedProgress->Set(0, 100, pginfo->GetWatchedPercent());
887 
888  // Handle artwork
889  QString arthost;
890  for (size_t i = 0; i < kNumArtImages; i++)
891  {
892  if (!m_artImage[i])
893  continue;
894 
895  if (arthost.isEmpty())
896  {
897  arthost = (!m_artHostOverride.isEmpty()) ?
898  m_artHostOverride : pginfo->GetHostname();
899  }
900 
901  QString fn = m_helper.LocateArtwork(
902  pginfo->GetInetRef(), pginfo->GetSeason(),
903  (VideoArtworkType)i, pginfo);
904 
905  if (fn.isEmpty())
906  {
907  m_artTimer[i]->stop();
908  m_artImage[i]->Reset();
909  }
910  else if (m_artImage[i]->GetFilename() != fn)
911  {
912  m_artImage[i]->SetFilename(fn);
913  m_artTimer[i]->start(s_artDelay[i]);
914  }
915  }
916 
917  updateIcons(pginfo);
918  }
919 }
920 
922 {
923  auto *pginfo = item->GetData().value<ProgramInfo*>();
924  if (item->GetText("is_item_initialized").isNull())
925  {
926  QMap<AudioProps, QString> audioFlags;
927  audioFlags[AUD_DOLBY] = "dolby";
928  audioFlags[AUD_SURROUND] = "surround";
929  audioFlags[AUD_STEREO] = "stereo";
930  audioFlags[AUD_MONO] = "mono";
931 
932  QMap<VideoProps, QString> codecFlags;
933  codecFlags[VID_MPEG2] = "mpeg2";
934  codecFlags[VID_AVC] = "avc";
935  codecFlags[VID_HEVC] = "hevc";
936 
937  QMap<SubtitleProps, QString> subtitleFlags;
938  subtitleFlags[SUB_SIGNED] = "deafsigned";
939  subtitleFlags[SUB_ONSCREEN] = "onscreensub";
940  subtitleFlags[SUB_NORMAL] = "subtitles";
941  subtitleFlags[SUB_HARDHEAR] = "cc";
942 
943  QString groupname =
944  m_groupList->GetItemCurrent()->GetData().toString();
945 
946  QString state = extract_main_state(*pginfo, m_player);
947 
948  item->SetFontState(state);
949 
950  InfoMap infoMap;
951  pginfo->ToMap(infoMap);
952  item->SetTextFromMap(infoMap);
953 
954  QString tempSubTitle = extract_subtitle(*pginfo, groupname);
955 
956  if (groupname == pginfo->GetTitle().toLower())
957  {
958  item->SetText(tempSubTitle, "titlesubtitle");
959  // titlesubtitle will just have the subtitle, so put the full
960  // string in titlesubtitlefull, when a theme can then "depend" on.
961  item->SetText(pginfo->toString(ProgramInfo::kTitleSubtitle, " - "),
962  "titlesubtitlefull");
963  }
964 
965  item->DisplayState(state, "status");
966 
967  item->DisplayState(QString::number(pginfo->GetStars(10)),
968  "ratingstate");
969 
970  SetItemIcons(item, pginfo);
971 
972  QMap<AudioProps, QString>::iterator ait;
973  for (ait = audioFlags.begin(); ait != audioFlags.end(); ++ait)
974  {
975  if (pginfo->GetAudioProperties() & ait.key())
976  item->DisplayState(ait.value(), "audioprops");
977  }
978 
979  uint props = pginfo->GetVideoProperties();
980 
981  QMap<VideoProps, QString>::iterator cit;
982  for (cit = codecFlags.begin(); cit != codecFlags.end(); ++cit)
983  {
984  if (props & cit.key())
985  {
986  item->DisplayState(cit.value(), "videoprops");
987  item->DisplayState(cit.value(), "codecprops");
988  }
989  }
990 
991  if (props & VID_PROGRESSIVE)
992  {
993  item->DisplayState("progressive", "videoprops");
994  if (props & VID_4K)
995  item->DisplayState("uhd4Kp", "videoprops");
996  if (props & VID_1080)
997  item->DisplayState("hd1080p", "videoprops");
998  }
999  else
1000  {
1001  if (props & VID_4K)
1002  item->DisplayState("uhd4Ki", "videoprops");
1003  if (props & VID_1080)
1004  item->DisplayState("hd1080i", "videoprops");
1005  }
1006  if (props & VID_720)
1007  item->DisplayState("hd720", "videoprops");
1008  if (!(props & (VID_4K | VID_1080 | VID_720)))
1009  {
1010  if (props & VID_HDTV)
1011  item->DisplayState("hdtv", "videoprops");
1012  else if (props & VID_WIDESCREEN)
1013  item->DisplayState("widescreen", "videoprops");
1014  else
1015  item->DisplayState("sd", "videoprops");
1016  }
1017 
1018  QMap<SubtitleProps, QString>::iterator sit;
1019  for (sit = subtitleFlags.begin(); sit != subtitleFlags.end(); ++sit)
1020  {
1021  if (pginfo->GetSubtitleType() & sit.key())
1022  item->DisplayState(sit.value(), "subtitletypes");
1023  }
1024 
1025  item->DisplayState(pginfo->GetCategoryTypeString(), "categorytype");
1026 
1027  // Mark this button list item as initialized.
1028  item->SetText("yes", "is_item_initialized");
1029  }
1030 
1031 }
1032 
1034 {
1035  auto *pginfo = item->GetData().value<ProgramInfo*>();
1036 
1037  ItemLoaded(item);
1038  // Job status (recording, transcoding, flagging)
1039  QString job = extract_job_state(*pginfo);
1040  item->DisplayState(job, "jobstate");
1041 
1042  // Flagging status (queued, running, no, yes)
1043  item->DisplayState(extract_commflag_state(*pginfo), "commflagged");
1044 
1045  const auto watchedPercent = pginfo->GetWatchedPercent();
1046  const bool showProgress = watchedPercent && (m_alwaysShowWatchedProgress || !pginfo->IsWatched());
1047  item->SetProgress1(0, showProgress ? 100 : 0, watchedPercent);
1048  item->SetProgress2(0, 100, pginfo->GetRecordedPercent());
1049 
1050  MythUIButtonListItem *sel_item = item->parent()->GetItemCurrent();
1051  if ((item != sel_item) && item->GetImageFilename("preview").isEmpty() &&
1052  (asAvailable == pginfo->GetAvailableStatus()))
1053  {
1054  QString token = m_helper.GetPreviewImage(*pginfo, true);
1055  if (token.isEmpty())
1056  return;
1057 
1058  m_previewTokens.insert(token);
1059  // now make sure selected item is still at the top of the queue
1060  auto *sel_pginfo = sel_item->GetData().value<ProgramInfo*>();
1061  if (sel_pginfo && sel_item->GetImageFilename("preview").isEmpty() &&
1062  (asAvailable == sel_pginfo->GetAvailableStatus()))
1063  {
1064  m_previewTokens.insert(m_helper.GetPreviewImage(*sel_pginfo, false));
1065  }
1066  }
1067 }
1068 
1069 
1076 void PlaybackBox::HandlePreviewEvent(const QStringList &list)
1077 {
1078  if (list.size() < 5)
1079  {
1080  LOG(VB_GENERAL, LOG_ERR, "HandlePreviewEvent() -- too few args");
1081  for (uint i = 0; i < (uint) list.size(); i++)
1082  {
1083  LOG(VB_GENERAL, LOG_INFO, QString("%1: %2")
1084  .arg(i).arg(list[i]));
1085  }
1086  return;
1087  }
1088 
1089  uint recordingID = list[0].toUInt();
1090  const QString& previewFile = list[1];
1091  const QString& message = list[2];
1092 
1093  bool found = false;
1094  for (uint i = 4; i < (uint) list.size(); i++)
1095  {
1096  const QString& token = list[i];
1097  QSet<QString>::iterator it = m_previewTokens.find(token);
1098  if (it != m_previewTokens.end())
1099  {
1100  found = true;
1101  m_previewTokens.erase(it);
1102  }
1103  }
1104 
1105  if (!found)
1106  {
1107  QString tokens("\n\t\t\ttokens: ");
1108  for (uint i = 4; i < (uint) list.size(); i++)
1109  tokens += list[i] + ", ";
1110  LOG(VB_GENERAL, LOG_DEBUG, LOC +
1111  "Ignoring PREVIEW_SUCCESS, no matcing token" + tokens);
1112  return;
1113  }
1114 
1115  if (previewFile.isEmpty())
1116  {
1117  LOG(VB_GENERAL, LOG_ERR, LOC +
1118  "Ignoring PREVIEW_SUCCESS, no preview file.");
1119  return;
1120  }
1121 
1123  MythUIButtonListItem *item = nullptr;
1124 
1125  if (info)
1126  item = m_recordingList->GetItemByData(QVariant::fromValue(info));
1127 
1128  if (!item)
1129  {
1130  LOG(VB_GENERAL, LOG_DEBUG, LOC +
1131  "Ignoring PREVIEW_SUCCESS, item no longer on screen.");
1132  }
1133 
1134  if (item)
1135  {
1136  LOG(VB_GUI, LOG_INFO, LOC + QString("Loading preview %1,\n\t\t\tmsg %2")
1137  .arg(previewFile, message));
1138 
1139  item->SetImage(previewFile, "preview", true);
1140 
1141  if ((GetFocusWidget() == m_recordingList) &&
1142  (m_recordingList->GetItemCurrent() == item) &&
1144  {
1145  m_previewImage->SetFilename(previewFile);
1146  m_previewImage->Load(true, true);
1147  }
1148  }
1149 }
1150 
1152 {
1153  uint32_t flags = FL_NONE;
1154 
1155  if (pginfo)
1156  flags = pginfo->GetProgramFlags();
1157 
1158  QMap <QString, int>::iterator it;
1159  QMap <QString, int> iconMap;
1160 
1161  iconMap["commflagged"] = FL_COMMFLAG;
1162  iconMap["cutlist"] = FL_CUTLIST;
1163  iconMap["autoexpire"] = FL_AUTOEXP;
1164  iconMap["processing"] = FL_COMMPROCESSING;
1165  iconMap["editing"] = FL_EDITING;
1166  iconMap["bookmark"] = FL_BOOKMARK;
1167  iconMap["inuse"] = (FL_INUSERECORDING |
1168  FL_INUSEPLAYING |
1169  FL_INUSEOTHER);
1170  iconMap["transcoded"] = FL_TRANSCODED;
1171  iconMap["watched"] = FL_WATCHED;
1172  iconMap["preserved"] = FL_PRESERVED;
1173 
1174  MythUIImage *iconImage = nullptr;
1175  MythUIStateType *iconState = nullptr;
1176  for (it = iconMap.begin(); it != iconMap.end(); ++it)
1177  {
1178  iconImage = dynamic_cast<MythUIImage *>(GetChild(it.key()));
1179  if (iconImage)
1180  iconImage->SetVisible((flags & (*it)) != 0U);
1181 
1182  iconState = dynamic_cast<MythUIStateType *>(GetChild(it.key()));
1183  if (iconState)
1184  {
1185  if (flags & (*it))
1186  iconState->DisplayState("yes");
1187  else
1188  iconState->DisplayState("no");
1189  }
1190  }
1191 
1192  iconMap.clear();
1193  // Add prefix to ensure iteration order in case 2 or more properties set
1194  iconMap["1dolby"] = AUD_DOLBY;
1195  iconMap["2surround"] = AUD_SURROUND;
1196  iconMap["3stereo"] = AUD_STEREO;
1197  iconMap["4mono"] = AUD_MONO;
1198 
1199  iconState = dynamic_cast<MythUIStateType *>(GetChild("audioprops"));
1200  bool haveIcon = false;
1201  if (pginfo && iconState)
1202  {
1203  for (it = iconMap.begin(); it != iconMap.end(); ++it)
1204  {
1205  if (pginfo->GetAudioProperties() & (*it))
1206  {
1207  if (iconState->DisplayState(it.key().mid(1)))
1208  {
1209  haveIcon = true;
1210  break;
1211  }
1212  }
1213  }
1214  }
1215 
1216  if (iconState && !haveIcon)
1217  iconState->Reset();
1218 
1219  iconState = dynamic_cast<MythUIStateType *>(GetChild("videoprops"));
1220  if (pginfo && iconState)
1221  {
1222  haveIcon = false;
1223  uint props = pginfo->GetVideoProperties();
1224 
1225  iconMap.clear();
1226  if (props & VID_PROGRESSIVE)
1227  {
1228  iconMap["uhd4Kp"] = VID_4K;
1229  iconMap["hd1080p"] = VID_1080;
1230  }
1231  else
1232  {
1233  iconMap["uhd4Ki"] = VID_4K;
1234  iconMap["hd1080i"] = VID_1080;
1235  }
1236  iconMap["hd1080"] = VID_1080;
1237  iconMap["hd720"] = VID_720;
1238  iconMap["hdtv"] = VID_HDTV;
1239  iconMap["widescreen"] = VID_WIDESCREEN;
1240 
1241  for (it = iconMap.begin(); it != iconMap.end(); ++it)
1242  {
1243  if (props & (*it))
1244  {
1245  if (iconState->DisplayState(it.key()))
1246  {
1247  haveIcon = true;
1248  break;
1249  }
1250  }
1251  }
1252 
1253  if (!haveIcon)
1254  iconState->Reset();
1255  }
1256 
1257  iconMap.clear();
1258  iconMap["damaged"] = VID_DAMAGED;
1259 
1260  iconState = dynamic_cast<MythUIStateType *>(GetChild("videoquality"));
1261  haveIcon = false;
1262  if (pginfo && iconState)
1263  {
1264  for (it = iconMap.begin(); it != iconMap.end(); ++it)
1265  {
1266  if (pginfo->GetVideoProperties() & (*it))
1267  {
1268  if (iconState->DisplayState(it.key()))
1269  {
1270  haveIcon = true;
1271  break;
1272  }
1273  }
1274  }
1275  }
1276 
1277  if (iconState && !haveIcon)
1278  iconState->Reset();
1279  iconMap.clear();
1280  iconMap["deafsigned"] = SUB_SIGNED;
1281  iconMap["onscreensub"] = SUB_ONSCREEN;
1282  iconMap["subtitles"] = SUB_NORMAL;
1283  iconMap["cc"] = SUB_HARDHEAR;
1284 
1285  iconState = dynamic_cast<MythUIStateType *>(GetChild("subtitletypes"));
1286  haveIcon = false;
1287  if (pginfo && iconState)
1288  {
1289  for (it = iconMap.begin(); it != iconMap.end(); ++it)
1290  {
1291  if (pginfo->GetSubtitleType() & (*it))
1292  {
1293  if (iconState->DisplayState(it.key()))
1294  {
1295  haveIcon = true;
1296  break;
1297  }
1298  }
1299  }
1300  }
1301 
1302  if (iconState && !haveIcon)
1303  iconState->Reset();
1304 
1305  iconState = dynamic_cast<MythUIStateType *>(GetChild("categorytype"));
1306  if (iconState)
1307  {
1308  if (!(pginfo && iconState->DisplayState(pginfo->GetCategoryTypeString())))
1309  iconState->Reset();
1310  }
1311 }
1312 
1314 {
1315  return GetChild("freereport") || GetChild("usedbar");
1316 }
1317 
1319 {
1320  MythUIText *freereportText =
1321  dynamic_cast<MythUIText*>(GetChild("freereport"));
1322  MythUIProgressBar *usedProgress =
1323  dynamic_cast<MythUIProgressBar *>(GetChild("usedbar"));
1324 
1325  // If the theme doesn't have these widgets,
1326  // don't waste time querying the backend...
1327  if (!freereportText && !usedProgress && !GetChild("diskspacetotal") &&
1328  !GetChild("diskspaceused") && !GetChild("diskspacefree") &&
1329  !GetChild("diskspacepercentused") && !GetChild("diskspacepercentfree"))
1330  return;
1331 
1332  auto freeSpaceTotal = (double) m_helper.GetFreeSpaceTotalMB();
1333  auto freeSpaceUsed = (double) m_helper.GetFreeSpaceUsedMB();
1334 
1335  QLocale locale = gCoreContext->GetQLocale();
1336  InfoMap usageMap;
1337  usageMap["diskspacetotal"] = locale.toString((freeSpaceTotal / 1024.0),
1338  'f', 2);
1339  usageMap["diskspaceused"] = locale.toString((freeSpaceUsed / 1024.0),
1340  'f', 2);
1341  usageMap["diskspacefree"] = locale.toString(
1342  ((freeSpaceTotal - freeSpaceUsed) / 1024.0),
1343  'f', 2);
1344 
1345  double perc = 0.0;
1346  if (freeSpaceTotal > 0.0)
1347  perc = (100.0 * freeSpaceUsed) / freeSpaceTotal;
1348 
1349  usageMap["diskspacepercentused"] = QString::number((int)perc);
1350  usageMap["diskspacepercentfree"] = QString::number(100 - (int)perc);
1351 
1352  QString size = locale.toString(((freeSpaceTotal - freeSpaceUsed) / 1024.0),
1353  'f', 2);
1354 
1355  QString usestr = tr("%1% used, %2 GB free", "Diskspace")
1356  .arg(QString::number((int)perc),
1357  size);
1358 
1359  if (freereportText)
1360  freereportText->SetText(usestr);
1361 
1362  if (usedProgress)
1363  {
1364  usedProgress->SetTotal((int)freeSpaceTotal);
1365  usedProgress->SetUsed((int)freeSpaceUsed);
1366  }
1367 
1368  SetTextFromMap(usageMap);
1369 }
1370 
1371 /*
1372  * \fn PlaybackBox::updateUIRecGroupList(void)
1373  * \brief called when the list of recording groups may have changed
1374  */
1376 {
1377  if (m_recGroupIdx < 0 || !m_recgroupList || m_recGroups.size() < 2)
1378  return;
1379 
1380  QSignalBlocker blocker(m_recgroupList);
1381 
1382  m_recgroupList->Reset();
1383 
1384  int idx = 0;
1385  QStringList::iterator it = m_recGroups.begin();
1386  for (; it != m_recGroups.end(); (++it), (++idx))
1387  {
1388  const QString& key = (*it);
1389  QString tmp = (key == "All Programs") ? "All" : key;
1390  QString name = ProgramInfo::i18n(tmp);
1391 
1392  if (m_recGroups.size() == 2 && key == "Default")
1393  continue; // All and Default will be the same, so only show All
1394 
1395  auto *item = new MythUIButtonListItem(m_recgroupList, name,
1396  QVariant::fromValue(key));
1397 
1398  if (idx == m_recGroupIdx)
1400  item->SetText(name);
1401  }
1402 }
1403 
1404 void PlaybackBox::UpdateUIGroupList(const QStringList &groupPreferences)
1405 {
1406  m_groupList->Reset();
1407 
1408  if (!m_titleList.isEmpty())
1409  {
1410  int best_pref = INT_MAX;
1411  int sel_idx = 0;
1412  QStringList::iterator it;
1413  for (it = m_titleList.begin(); it != m_titleList.end(); ++it)
1414  {
1415  const QString& groupname = (*it);
1416 
1417  auto *item = new MythUIButtonListItem(m_groupList, "",
1418  QVariant::fromValue(groupname.toLower()));
1419 
1420  int pref = groupPreferences.indexOf(groupname.toLower());
1421  if ((pref >= 0) && (pref < best_pref))
1422  {
1423  best_pref = pref;
1424  sel_idx = m_groupList->GetItemPos(item);
1425  m_currentGroup = groupname.toLower();
1426  }
1427 
1428  QString displayName = groupname;
1429  if (displayName.isEmpty())
1430  {
1431  if (m_recGroup == "All Programs")
1432  displayName = ProgramInfo::i18n("All Programs");
1433  else
1434  displayName = ProgramInfo::i18n("All Programs - %1")
1435  .arg(m_groupDisplayName);
1436  }
1437 
1438  item->SetText(groupname, "groupname");
1439  item->SetText(displayName, "name");
1440  item->SetText(displayName);
1441 
1442  int count = m_progLists[groupname.toLower()].size();
1443  item->SetText(QString::number(count), "reccount");
1444  }
1445 
1446  m_needUpdate = true;
1447  m_groupList->SetItemCurrent(sel_idx);
1448  // We need to explicitly call updateRecList in this case,
1449  // since 0 is selected by default, and we need updateRecList
1450  // to be called with m_needUpdate set.
1451  if (!sel_idx)
1453  }
1454 }
1455 
1457 {
1458  QString newRecGroup = sel_item->GetData().toString();
1459  displayRecGroup(newRecGroup);
1460 }
1461 
1463 {
1464  QString nextGroup;
1465  m_recGroupsLock.lock();
1466  if (m_recGroupIdx >= 0 && !m_recGroups.empty())
1467  {
1468  if (++m_recGroupIdx >= m_recGroups.size())
1469  m_recGroupIdx = 0;
1470  nextGroup = m_recGroups[m_recGroupIdx];
1471  }
1472  m_recGroupsLock.unlock();
1473 
1474  if (!nextGroup.isEmpty())
1475  displayRecGroup(nextGroup);
1476 }
1477 
1479 {
1480  if (!sel_item)
1481  return;
1482 
1483  QString groupname = sel_item->GetData().toString();
1484  QString grouplabel = sel_item->GetText();
1485 
1486  updateGroupInfo(groupname, grouplabel);
1487 
1488  if (((m_currentGroup == groupname) && !m_needUpdate) ||
1490  return;
1491 
1492  m_needUpdate = false;
1493 
1494  if (!m_isFilling)
1495  m_currentGroup = groupname;
1496 
1498 
1499  ProgramMap::iterator pmit = m_progLists.find(groupname);
1500  if (pmit == m_progLists.end())
1501  return;
1502 
1503  ProgramList &progList = *pmit;
1504 
1505  for (auto & prog : progList)
1506  {
1507  if (prog->GetAvailableStatus() == asPendingDelete ||
1508  prog->GetAvailableStatus() == asDeleted)
1509  continue;
1510 
1511  new PlaybackBoxListItem(this, m_recordingList, prog);
1512  }
1514 
1515  if (m_noRecordingsText)
1516  {
1517  if (!progList.empty())
1519  else
1520  {
1521  QString txt = m_programInfoCache.empty() ?
1522  tr("There are no recordings available") :
1523  tr("There are no recordings in your current view");
1526  }
1527  }
1528 }
1529 
1530 static bool save_position(
1531  const MythUIButtonList *groupList, const MythUIButtonList *recordingList,
1532  QStringList &groupSelPref, QStringList &itemSelPref,
1533  QStringList &itemTopPref)
1534 {
1535  MythUIButtonListItem *prefSelGroup = groupList->GetItemCurrent();
1536  if (!prefSelGroup)
1537  return false;
1538 
1539  groupSelPref.push_back(prefSelGroup->GetData().toString());
1540  for (int i = groupList->GetCurrentPos();
1541  i < groupList->GetCount(); i++)
1542  {
1543  prefSelGroup = groupList->GetItemAt(i);
1544  if (prefSelGroup)
1545  groupSelPref.push_back(prefSelGroup->GetData().toString());
1546  }
1547 
1548  int curPos = recordingList->GetCurrentPos();
1549  for (int i = curPos; (i >= 0) && (i < recordingList->GetCount()); i++)
1550  {
1551  MythUIButtonListItem *item = recordingList->GetItemAt(i);
1552  auto *pginfo = item->GetData().value<ProgramInfo*>();
1553  itemSelPref.push_back(groupSelPref.front());
1554  itemSelPref.push_back(QString::number(pginfo->GetRecordingID()));
1555  }
1556  for (int i = curPos; (i >= 0) && (i < recordingList->GetCount()); i--)
1557  {
1558  MythUIButtonListItem *item = recordingList->GetItemAt(i);
1559  auto *pginfo = item->GetData().value<ProgramInfo*>();
1560  itemSelPref.push_back(groupSelPref.front());
1561  itemSelPref.push_back(QString::number(pginfo->GetRecordingID()));
1562  }
1563 
1564  int topPos = recordingList->GetTopItemPos();
1565  for (int i = topPos + 1; i >= topPos - 1; i--)
1566  {
1567  if (i >= 0 && i < recordingList->GetCount())
1568  {
1569  MythUIButtonListItem *item = recordingList->GetItemAt(i);
1570  auto *pginfo = item->GetData().value<ProgramInfo*>();
1571  if (i == topPos)
1572  {
1573  itemTopPref.push_front(QString::number(pginfo->GetRecordingID()));
1574  itemTopPref.push_front(groupSelPref.front());
1575  }
1576  else
1577  {
1578  itemTopPref.push_back(groupSelPref.front());
1579  itemTopPref.push_back(QString::number(pginfo->GetRecordingID()));
1580  }
1581  }
1582  }
1583 
1584  return true;
1585 }
1586 
1587 static void restore_position(
1588  MythUIButtonList *groupList, MythUIButtonList *recordingList,
1589  const QStringList &groupSelPref, const QStringList &itemSelPref,
1590  const QStringList &itemTopPref)
1591 {
1592  // If possible reselect the item selected before,
1593  // otherwise select the nearest available item.
1594  MythUIButtonListItem *prefSelGroup = groupList->GetItemCurrent();
1595  if (!prefSelGroup ||
1596  !groupSelPref.contains(prefSelGroup->GetData().toString()) ||
1597  !itemSelPref.contains(prefSelGroup->GetData().toString()))
1598  {
1599  return;
1600  }
1601 
1602  // the group is selected in UpdateUIGroupList()
1603  QString groupname = prefSelGroup->GetData().toString();
1604 
1605  // find best selection
1606  int sel = -1;
1607  for (uint i = 0; i+1 < (uint)itemSelPref.size(); i+=2)
1608  {
1609  if (itemSelPref[i] != groupname)
1610  continue;
1611 
1612  uint recordingID = itemSelPref[i+1].toUInt();
1613  for (uint j = 0; j < (uint)recordingList->GetCount(); j++)
1614  {
1615  MythUIButtonListItem *item = recordingList->GetItemAt(j);
1616  auto *pginfo = item->GetData().value<ProgramInfo*>();
1617  if (pginfo && (pginfo->GetRecordingID() == recordingID))
1618  {
1619  sel = j;
1620  i = itemSelPref.size();
1621  break;
1622  }
1623  }
1624  }
1625 
1626  // find best top item
1627  int top = -1;
1628  for (uint i = 0; i+1 < (uint)itemTopPref.size(); i+=2)
1629  {
1630  if (itemTopPref[i] != groupname)
1631  continue;
1632 
1633  uint recordingID = itemTopPref[i+1].toUInt();
1634  for (uint j = 0; j < (uint)recordingList->GetCount(); j++)
1635  {
1636  MythUIButtonListItem *item = recordingList->GetItemAt(j);
1637  auto *pginfo = item->GetData().value<ProgramInfo*>();
1638  if (pginfo && (pginfo->GetRecordingID() == recordingID))
1639  {
1640  top = j;
1641  i = itemTopPref.size();
1642  break;
1643  }
1644  }
1645  }
1646 
1647  if (sel >= 0)
1648  {
1649 #if 0
1650  LOG(VB_GENERAL, LOG_DEBUG, QString("Reselect success (%1,%2)")
1651  .arg(sel).arg(top));
1652 #endif
1653  recordingList->SetItemCurrent(sel, top);
1654  }
1655  else
1656  {
1657 #if 0
1658  LOG(VB_GENERAL, LOG_DEBUG, QString("Reselect failure (%1,%2)")
1659  .arg(sel).arg(top));
1660 #endif
1661  }
1662 }
1663 
1665 {
1666  m_isFilling = true;
1667 
1668  // Save selection, including next few items & groups
1669  QStringList groupSelPref;
1670  QStringList itemSelPref;
1671  QStringList itemTopPref;
1673  groupSelPref, itemSelPref, itemTopPref))
1674  {
1675  // If user wants to start in watchlist and watchlist is displayed, then
1676  // make it the current group
1678  groupSelPref.push_back(m_watchGroupLabel);
1679  }
1680 
1681  // Cache available status for later restoration
1682  QMap<uint, AvailableStatusType> asCache;
1683 
1684  if (!m_progLists.isEmpty())
1685  {
1686  for (auto & prog : m_progLists[""])
1687  {
1688  uint asRecordingID = prog->GetRecordingID();
1689  asCache[asRecordingID] = prog->GetAvailableStatus();
1690  }
1691  }
1692 
1693  m_progsInDB = 0;
1694  m_titleList.clear();
1695  m_progLists.clear();
1697  m_groupList->Reset();
1698  if (m_recgroupList)
1699  m_recgroupList->Reset();
1700  // Clear autoDelete for the "all" list since it will share the
1701  // objects with the title lists.
1702  m_progLists[""] = ProgramList(false);
1703  m_progLists[""].setAutoDelete(false);
1704 
1706  "DisplayGroupTitleSort", TitleSortAlphabetical);
1707 
1708  bool isAllProgsGroup = (m_recGroup == "All Programs");
1709  QMap<QString, QString> sortedList;
1710  QMap<int, QString> searchRule;
1711  QMap<int, QDateTime> recidLastEventTime;
1712  QMap<int, ProgramInfo*> recidWatchListProgram;
1713 
1715 
1716  if (!m_programInfoCache.empty())
1717  {
1718  QString sTitle;
1719 
1720  if ((m_viewMask & VIEW_SEARCHES))
1721  {
1722  MSqlQuery query(MSqlQuery::InitCon());
1723  query.prepare("SELECT recordid,title FROM record "
1724  "WHERE search > 0 AND search != :MANUAL;");
1725  query.bindValue(":MANUAL", kManualSearch);
1726 
1727  if (query.exec())
1728  {
1729  while (query.next())
1730  {
1731  QString tmpTitle = query.value(1).toString();
1732  tmpTitle.remove(RecordingInfo::kReSearchTypeName);
1733  searchRule[query.value(0).toInt()] = tmpTitle;
1734  }
1735  }
1736  }
1737 
1738  bool isCategoryFilter = (m_recGroupType[m_recGroup] == "category");
1739  bool isUnknownCategory = (m_recGroup == tr("Unknown"));
1740  bool isDeletedGroup = (m_recGroup == "Deleted");
1741  bool isLiveTvGroup = (m_recGroup == "LiveTV");
1742 
1743  std::vector<ProgramInfo*> list;
1744  bool newest_first = (0==m_allOrder);
1745  m_programInfoCache.GetOrdered(list, newest_first);
1746  for (auto *p : list)
1747  {
1748  if (p->IsDeletePending())
1749  continue;
1750 
1751  m_progsInDB++;
1752 
1753  const QString& pRecgroup(p->GetRecordingGroup());
1754  const bool isLiveTVProg(pRecgroup == "LiveTV");
1755 
1756  // Never show anything from unauthorised passworded groups
1757  QString password = getRecGroupPassword(pRecgroup);
1758  if (m_curGroupPassword != password && !password.isEmpty())
1759  continue;
1760 
1761  if (pRecgroup == "Deleted")
1762  {
1763  // Filter nothing from Deleted group
1764  // Never show Deleted recs anywhere else
1765  if (!isDeletedGroup)
1766  continue;
1767  }
1768  // Optionally ignore LiveTV programs if not viewing LiveTV group
1769  else if (!(m_viewMask & VIEW_LIVETVGRP) &&
1770  !isLiveTvGroup && isLiveTVProg)
1771  { // NOLINT(bugprone-branch-clone)
1772  continue;
1773  }
1774  // Optionally ignore watched
1775  else if (!(m_viewMask & VIEW_WATCHED) && p->IsWatched())
1776  {
1777  continue;
1778  }
1779  else if (isCategoryFilter)
1780  {
1781  // Filter by category
1782  if (isUnknownCategory ? !p->GetCategory().isEmpty()
1783  : p->GetCategory() != m_recGroup)
1784  continue;
1785  }
1786  // Filter by recgroup
1787  else if (!isAllProgsGroup && pRecgroup != m_recGroup)
1788  {
1789  continue;
1790  }
1791 
1792  if (p->GetTitle().isEmpty())
1793  p->SetTitle(tr("_NO_TITLE_"));
1794 
1795  if (m_viewMask != VIEW_NONE && (!isLiveTVProg || isLiveTvGroup))
1796  {
1797  m_progLists[""].push_front(p);
1798  }
1799 
1800  uint asRecordingID = p->GetRecordingID();
1801  if (asCache.contains(asRecordingID))
1802  p->SetAvailableStatus(asCache[asRecordingID], "UpdateUILists");
1803  else
1804  p->SetAvailableStatus(asAvailable, "UpdateUILists");
1805 
1806  if (!isLiveTvGroup && isLiveTVProg && (m_viewMask & VIEW_LIVETVGRP))
1807  {
1808  QString tmpTitle = tr("Live TV");
1809  sortedList[tmpTitle.toLower()] = tmpTitle;
1810  m_progLists[tmpTitle.toLower()].push_front(p);
1811  m_progLists[tmpTitle.toLower()].setAutoDelete(false);
1812  continue;
1813  }
1814 
1815  // Show titles
1816  if ((m_viewMask & VIEW_TITLES) && (!isLiveTVProg || isLiveTvGroup))
1817  {
1818  sTitle = construct_sort_title(
1819  p->GetTitle(), p->GetSortTitle(), m_viewMask, titleSort,
1820  p->GetRecordingPriority());
1821  sTitle = sTitle.toLower();
1822 
1823  if (!sortedList.contains(sTitle))
1824  sortedList[sTitle] = p->GetTitle();
1825  m_progLists[sortedList[sTitle].toLower()].push_front(p);
1826  m_progLists[sortedList[sTitle].toLower()].setAutoDelete(false);
1827  }
1828 
1829  // Show recording groups
1830  if ((m_viewMask & VIEW_RECGROUPS) &&
1831  !pRecgroup.isEmpty() && !isLiveTVProg)
1832  {
1833  sortedList[pRecgroup.toLower()] = pRecgroup;
1834  m_progLists[pRecgroup.toLower()].push_front(p);
1835  m_progLists[pRecgroup.toLower()].setAutoDelete(false);
1836  }
1837 
1838  // Show categories
1839  if (((m_viewMask & VIEW_CATEGORIES) != 0) && !p->GetCategory().isEmpty())
1840  {
1841  QString catl = p->GetCategory().toLower();
1842  sortedList[catl] = p->GetCategory();
1843  m_progLists[catl].push_front(p);
1844  m_progLists[catl].setAutoDelete(false);
1845  }
1846 
1847  if (((m_viewMask & VIEW_SEARCHES) != 0) &&
1848  !searchRule[p->GetRecordingRuleID()].isEmpty() &&
1849  p->GetTitle() != searchRule[p->GetRecordingRuleID()])
1850  { // Show search rules
1851  QString tmpTitle = QString("(%1)")
1852  .arg(searchRule[p->GetRecordingRuleID()]);
1853  sortedList[tmpTitle.toLower()] = tmpTitle;
1854  m_progLists[tmpTitle.toLower()].push_front(p);
1855  m_progLists[tmpTitle.toLower()].setAutoDelete(false);
1856  }
1857 
1858  if ((m_viewMask & VIEW_WATCHLIST) &&
1859  !isLiveTVProg && pRecgroup != "Deleted")
1860  {
1861  int rid = p->GetRecordingRuleID();
1862  auto letIt = recidLastEventTime.find(rid);
1863  if (letIt == recidLastEventTime.end() || *letIt < p->GetLastModifiedTime())
1864  {
1865  recidLastEventTime[rid] = p->GetLastModifiedTime();
1866  }
1867 
1868  if (m_watchListAutoExpire && !p->IsAutoExpirable())
1869  {
1870  p->SetRecordingPriority2(wlExpireOff);
1871  LOG(VB_FILE, LOG_INFO, QString("Auto-expire off: %1")
1872  .arg(p->GetTitle()));
1873  }
1874  else if (p->IsWatched())
1875  {
1876  p->SetRecordingPriority2(wlWatched);
1877  LOG(VB_FILE, LOG_INFO,
1878  QString("Marked as 'watched': %1")
1879  .arg(p->GetTitle()));
1880  }
1881  else
1882  {
1883  auto wlpIt = recidWatchListProgram.find(rid);
1884  if (wlpIt == recidWatchListProgram.end())
1885  {
1886  recidWatchListProgram[rid] = p;
1887  }
1888  else if(comp_season(p, *wlpIt) > 0)
1889  {
1890  (*wlpIt)->SetRecordingPriority2(wlEarlier);
1891  LOG(VB_FILE, LOG_INFO,
1892  QString("Not the earliest: %1")
1893  .arg((*wlpIt)->GetTitle()));
1894 
1895  recidWatchListProgram[rid] = p;
1896  }
1897  else
1898  {
1899  p->SetRecordingPriority2(wlEarlier);
1900  LOG(VB_FILE, LOG_INFO,
1901  QString("Not the earliest: %1")
1902  .arg(p->GetTitle()));
1903  }
1904  }
1905  }
1906  }
1907 
1908  if ((m_viewMask & VIEW_WATCHLIST) && !recidWatchListProgram.empty())
1909  {
1910  for (auto *p : std::as_const(recidWatchListProgram))
1911  {
1912  m_progLists[m_watchGroupLabel].push_back(p);
1913  }
1914 
1915  m_progLists[m_watchGroupLabel].setAutoDelete(false);
1916  }
1917  }
1918 
1919  if (sortedList.empty())
1920  {
1921  LOG(VB_GENERAL, LOG_WARNING, LOC + "SortedList is Empty");
1922  m_progLists[""];
1923  m_titleList << "";
1924  m_playList.clear();
1925  if (!isAllProgsGroup)
1927 
1929  UpdateUIGroupList(groupSelPref);
1930 
1931  m_isFilling = false;
1932  return false;
1933  }
1934 
1935  QString episodeSort = gCoreContext->GetSetting("PlayBoxEpisodeSort", "Date");
1936 
1937  if (episodeSort == "OrigAirDate")
1938  {
1939  QMap<QString, ProgramList>::Iterator Iprog;
1940  for (Iprog = m_progLists.begin(); Iprog != m_progLists.end(); ++Iprog)
1941  {
1942  if (!Iprog.key().isEmpty())
1943  {
1944  std::stable_sort((*Iprog).begin(), (*Iprog).end(),
1945  (m_listOrder == 0) ?
1948  }
1949  }
1950  }
1951  else if (episodeSort == "Id")
1952  {
1953  QMap<QString, ProgramList>::Iterator Iprog;
1954  for (Iprog = m_progLists.begin(); Iprog != m_progLists.end(); ++Iprog)
1955  {
1956  if (!Iprog.key().isEmpty())
1957  {
1958  std::stable_sort((*Iprog).begin(), (*Iprog).end(),
1959  (m_listOrder == 0) ?
1962  }
1963  }
1964  }
1965  else if (episodeSort == "Date")
1966  {
1967  QMap<QString, ProgramList>::iterator it;
1968  for (it = m_progLists.begin(); it != m_progLists.end(); ++it)
1969  {
1970  if (!it.key().isEmpty())
1971  {
1972  std::stable_sort((*it).begin(), (*it).end(),
1973  (!m_listOrder) ?
1976  }
1977  }
1978  }
1979  else if (episodeSort == "Season")
1980  {
1981  QMap<QString, ProgramList>::iterator it;
1982  for (it = m_progLists.begin(); it != m_progLists.end(); ++it)
1983  {
1984  if (!it.key().isEmpty())
1985  {
1986  std::stable_sort((*it).begin(), (*it).end(),
1987  (!m_listOrder) ?
1990  }
1991  }
1992  }
1993 
1994  if (!m_progLists[m_watchGroupLabel].empty())
1995  {
1996  MSqlQuery query(MSqlQuery::InitCon());
1997  query.prepare("SELECT recordid, last_delete FROM record;");
1998 
1999  if (query.exec())
2000  {
2001  while (query.next())
2002  {
2003  int recid = query.value(0).toInt();
2004 
2005  QDateTime last_delete =
2006  MythDate::as_utc(query.value(1).toDateTime());
2007 
2008  if (last_delete.isValid())
2009  {
2010  auto it = recidLastEventTime.find(recid);
2011  if (it != recidLastEventTime.end() && last_delete > *it)
2012  {
2013  recidLastEventTime[recid] = last_delete;
2014  }
2015  }
2016  }
2017  }
2018 
2019  auto pit = m_progLists[m_watchGroupLabel].begin();
2020  while (pit != m_progLists[m_watchGroupLabel].end())
2021  {
2022  int recid = (*pit)->GetRecordingRuleID();
2023 
2024  (*pit)->SetRecordingPriority2(recidLastEventTime[recid].toSecsSinceEpoch()/60);
2025 
2026  LOG(VB_FILE, LOG_INFO, QString(" %1 %2 %3")
2027  .arg(MythDate::toString((*pit)->GetScheduledStartTime(),
2029  .arg((*pit)->GetRecordingPriority2())
2030  .arg((*pit)->GetTitle()));
2031 
2032  ++pit;
2033  }
2034 
2035  std::stable_sort(m_progLists[m_watchGroupLabel].begin(),
2038  }
2039 
2040  m_titleList = QStringList("");
2041  if (!m_progLists[m_watchGroupLabel].empty())
2043  if ((!m_progLists["livetv"].empty()) &&
2044  (std::find(sortedList.cbegin(), sortedList.cend(), tr("Live TV"))
2045  == sortedList.cend()))
2046  m_titleList << tr("Live TV");
2047  m_titleList << sortedList.values();
2048 
2049  // Populate list of recording groups
2050  if (!m_programInfoCache.empty())
2051  {
2052  QMutexLocker locker(&m_recGroupsLock);
2053 
2054  m_recGroups.clear();
2055  m_recGroupIdx = -1;
2056 
2057  m_recGroups.append("All Programs");
2058 
2059  MSqlQuery query(MSqlQuery::InitCon());
2060 
2061  query.prepare("SELECT distinct recgroup from recorded WHERE "
2062  "deletepending = 0 ORDER BY recgroup");
2063  if (query.exec())
2064  {
2065  QString name;
2066  while (query.next())
2067  {
2068  name = query.value(0).toString();
2069  if (name != "Deleted" && name != "LiveTV" && !name.startsWith('.'))
2070  {
2071  m_recGroups.append(name);
2072  m_recGroupType[name] = "recgroup";
2073  }
2074  }
2075 
2077  m_recGroupIdx = std::max(m_recGroupIdx, 0);
2078  }
2079  }
2080 
2082  UpdateUIGroupList(groupSelPref);
2083  UpdateUsageUI();
2084 
2085  for (uint id : std::as_const(m_playList))
2086  {
2087  ProgramInfo *pginfo = FindProgramInUILists(id);
2088  if (!pginfo)
2089  continue;
2090  MythUIButtonListItem *item =
2091  m_recordingList->GetItemByData(QVariant::fromValue(pginfo));
2092  if (item)
2093  item->DisplayState("yes", "playlist");
2094  }
2095 
2097  groupSelPref, itemSelPref, itemTopPref);
2098 
2099  m_isFilling = false;
2100 
2101  return true;
2102 }
2103 
2105 {
2106  if (Random)
2107  {
2108  m_playListPlay.clear();
2109  QList<uint> tmp = m_playList;
2110  while (!tmp.isEmpty())
2111  {
2112  unsigned int i = MythRandom(0, tmp.size() - 1);
2113  m_playListPlay.append(tmp[i]);
2114  tmp.removeAll(tmp[i]);
2115  }
2116  }
2117  else
2118  {
2120  }
2121 
2122  QCoreApplication::postEvent(
2123  this, new MythEvent("PLAY_PLAYLIST"));
2124 }
2125 
2127 {
2128  if (!item)
2129  item = m_recordingList->GetItemCurrent();
2130 
2131  if (!item)
2132  return;
2133 
2134  auto *pginfo = item->GetData().value<ProgramInfo *>();
2135 
2136  const bool ignoreBookmark = false;
2137  const bool ignoreProgStart = false;
2138  const bool ignoreLastPlayPos = false;
2139  const bool underNetworkControl = false;
2140  if (pginfo)
2141  PlayX(*pginfo, ignoreBookmark, ignoreProgStart, ignoreLastPlayPos,
2142  underNetworkControl);
2143 }
2144 
2146 {
2147  if (!item)
2148  item = m_recordingList->GetItemCurrent();
2149 
2150  if (!item)
2151  return;
2152 
2153  auto *pginfo = item->GetData().value<ProgramInfo *>();
2154 
2155  const bool ignoreBookmark = false;
2156  const bool ignoreProgStart = true;
2157  const bool ignoreLastPlayPos = true;
2158  const bool underNetworkControl = false;
2159  if (pginfo)
2160  PlayX(*pginfo, ignoreBookmark, ignoreProgStart, ignoreLastPlayPos,
2161  underNetworkControl);
2162 }
2163 
2165 {
2166  if (!item)
2167  item = m_recordingList->GetItemCurrent();
2168 
2169  if (!item)
2170  return;
2171 
2172  auto *pginfo = item->GetData().value<ProgramInfo *>();
2173 
2174  const bool ignoreBookmark = true;
2175  const bool ignoreProgStart = true;
2176  const bool ignoreLastPlayPos = true;
2177  const bool underNetworkControl = false;
2178  if (pginfo)
2179  PlayX(*pginfo, ignoreBookmark, ignoreProgStart, ignoreLastPlayPos,
2180  underNetworkControl);
2181 }
2182 
2184 {
2185  if (!item)
2186  item = m_recordingList->GetItemCurrent();
2187 
2188  if (!item)
2189  return;
2190 
2191  auto *pginfo = item->GetData().value<ProgramInfo *>();
2192 
2193  const bool ignoreBookmark = true;
2194  const bool ignoreProgStart = true;
2195  const bool ignoreLastPlayPos = false;
2196  const bool underNetworkControl = false;
2197  if (pginfo)
2198  PlayX(*pginfo, ignoreBookmark, ignoreProgStart, ignoreLastPlayPos,
2199  underNetworkControl);
2200 }
2201 
2202 void PlaybackBox::PlayX(const ProgramInfo &pginfo,
2203  bool ignoreBookmark,
2204  bool ignoreProgStart,
2205  bool ignoreLastPlayPos,
2206  bool underNetworkControl)
2207 {
2208  if (!m_player)
2209  {
2210  Play(pginfo, false, ignoreBookmark, ignoreProgStart, ignoreLastPlayPos, underNetworkControl);
2211  return;
2212  }
2213 
2214  if (!m_player->IsSameProgram(&pginfo))
2215  {
2217  m_playerSelectedNewShow.push_back(ignoreBookmark ? "1" : "0");
2218  m_playerSelectedNewShow.push_back(underNetworkControl ? "1" : "0");
2219  // XXX add anything for ignoreProgStart and ignoreLastPlayPos?
2220  }
2221  Close();
2222 }
2223 
2225 {
2226  ProgramInfo *pginfo = GetCurrentProgram();
2227  if (pginfo)
2228  pginfo->SaveBookmark(0);
2229 }
2230 
2232 {
2233  ProgramInfo *pginfo = GetCurrentProgram();
2234  if (pginfo)
2235  pginfo->SaveLastPlayPos(0);
2236 }
2237 
2239 {
2240  ProgramInfo *pginfo = GetCurrentProgram();
2241  if (pginfo)
2242  m_helper.StopRecording(*pginfo);
2243 }
2244 
2246 {
2247  if (!item)
2248  return;
2249 
2250  auto *pginfo = item->GetData().value<ProgramInfo *>();
2251 
2252  if (!pginfo)
2253  return;
2254 
2255  if (pginfo->GetAvailableStatus() == asPendingDelete)
2256  {
2257  LOG(VB_GENERAL, LOG_ERR, QString("deleteSelected(%1) -- failed ")
2258  .arg(pginfo->toString(ProgramInfo::kTitleSubtitle)) +
2259  QString("availability status: %1 ")
2260  .arg(pginfo->GetAvailableStatus()));
2261 
2262  ShowOkPopup(tr("Cannot delete\n") +
2263  tr("This recording is already being deleted"));
2264  }
2265  else if (!pginfo->QueryIsDeleteCandidate())
2266  {
2267  QString byWho;
2268  pginfo->QueryIsInUse(byWho);
2269 
2270  LOG(VB_GENERAL, LOG_ERR, QString("deleteSelected(%1) -- failed ")
2271  .arg(pginfo->toString(ProgramInfo::kTitleSubtitle)) +
2272  QString("delete candidate: %1 in use by %2")
2273  .arg(pginfo->QueryIsDeleteCandidate()).arg(byWho));
2274 
2275  if (byWho.isEmpty())
2276  {
2277  ShowOkPopup(tr("Cannot delete\n") +
2278  tr("This recording is already being deleted"));
2279  }
2280  else
2281  {
2282  ShowOkPopup(tr("Cannot delete\n") +
2283  tr("This recording is currently in use by:") + "\n" +
2284  byWho);
2285  }
2286  }
2287  else
2288  {
2289  push_onto_del(m_delList, *pginfo);
2291  }
2292 }
2293 
2295 {
2296  ProgramInfo *pginfo = nullptr;
2297 
2299 
2300  if (!item)
2301  return nullptr;
2302 
2303  pginfo = item->GetData().value<ProgramInfo *>();
2304 
2305  if (!pginfo)
2306  return nullptr;
2307 
2308  return pginfo;
2309 }
2310 
2312 {
2313  if (!item)
2314  return;
2315 
2316  PlayFromAnyMark(item);
2317 }
2318 
2319 void PlaybackBox::popupClosed(const QString& which, int result)
2320 {
2321  m_menuDialog = nullptr;
2322 
2323  if (result == -2)
2324  {
2325  if (!m_doToggleMenu)
2326  {
2327  m_doToggleMenu = true;
2328  return;
2329  }
2330 
2331  if (which == "groupmenu")
2332  {
2333  ProgramInfo *pginfo = GetCurrentProgram();
2334  if (pginfo)
2335  {
2337 
2338  if ((asPendingDelete == pginfo->GetAvailableStatus()) ||
2339  (asDeleted == pginfo->GetAvailableStatus()) ||
2340  (asNotYetAvailable == pginfo->GetAvailableStatus()))
2341  {
2342  ShowAvailabilityPopup(*pginfo);
2343  }
2344  else
2345  {
2346  ShowActionPopup(*pginfo);
2347  m_doToggleMenu = false;
2348  }
2349  }
2350  }
2351  else if (which == "actionmenu")
2352  {
2353  ShowGroupPopup();
2354  m_doToggleMenu = false;
2355  }
2356  }
2357  else
2358  {
2359  m_doToggleMenu = true;
2360  }
2361 }
2362 
2364 {
2365  QString label = tr("Group List Menu");
2366 
2367  ProgramInfo *pginfo = GetCurrentProgram();
2368 
2369  m_popupMenu = new MythMenu(label, this, "groupmenu");
2370 
2371  m_popupMenu->AddItem(tr("Change Group Filter"),
2373 
2374  m_popupMenu->AddItem(tr("Change Group View"),
2376 
2377  if (m_recGroupType[m_recGroup] == "recgroup")
2378  m_popupMenu->AddItem(tr("Change Group Password"),
2380 
2381  if (!m_playList.isEmpty())
2382  {
2383  m_popupMenu->AddItem(tr("Playlist Options"), nullptr, createPlaylistMenu());
2384  }
2385  else if (!m_player)
2386  {
2387  if (GetFocusWidget() == m_groupList)
2388  {
2389  m_popupMenu->AddItem(tr("Add this Group to Playlist"),
2391  }
2392  else if (pginfo)
2393  {
2394  m_popupMenu->AddItem(tr("Add this recording to Playlist"),
2395  qOverload<>(&PlaybackBox::togglePlayListItem));
2396  }
2397  }
2398 
2399  m_popupMenu->AddItem(tr("Help (Status Icons)"), &PlaybackBox::showIconHelp);
2400 
2401  DisplayPopupMenu();
2402 }
2403 
2405  const ProgramInfo &rec,
2406  bool inPlaylist, bool ignoreBookmark, bool ignoreProgStart,
2407  bool ignoreLastPlayPos, bool underNetworkControl)
2408 {
2409  bool playCompleted = false;
2410 
2411  if (m_player)
2412  return true;
2413 
2414  if ((asAvailable != rec.GetAvailableStatus()) || !rec.GetFilesize() ||
2415  !rec.IsPathSet())
2416  {
2418  rec, (inPlaylist) ? kCheckForPlaylistAction : kCheckForPlayAction);
2419  return false;
2420  }
2421 
2422  for (size_t i = 0; i < kNumArtImages; i++)
2423  {
2424  if (!m_artImage[i])
2425  continue;
2426 
2427  m_artTimer[i]->stop();
2428  m_artImage[i]->Reset();
2429  }
2430 
2431  ProgramInfo tvrec(rec);
2432 
2433  m_playingSomething = true;
2434  int initIndex = m_recordingList->StopLoad();
2435 
2436  if (!gCoreContext->GetBoolSetting("UseProgStartMark", false))
2437  ignoreProgStart = true;
2438 
2439  uint flags =
2440  (inPlaylist ? kStartTVInPlayList : kStartTVNoFlags) |
2441  (underNetworkControl ? kStartTVByNetworkCommand : kStartTVNoFlags) |
2442  (ignoreLastPlayPos ? kStartTVIgnoreLastPlayPos : kStartTVNoFlags) |
2443  (ignoreProgStart ? kStartTVIgnoreProgStart : kStartTVNoFlags) |
2444  (ignoreBookmark ? kStartTVIgnoreBookmark : kStartTVNoFlags);
2445 
2446  playCompleted = TV::StartTV(&tvrec, flags);
2447 
2448  m_playingSomething = false;
2449  m_recordingList->LoadInBackground(initIndex);
2450 
2451  if (inPlaylist && !m_playListPlay.empty())
2452  {
2453  QCoreApplication::postEvent(
2454  this, new MythEvent("PLAY_PLAYLIST"));
2455  }
2456 
2457  if (m_needUpdate)
2459 
2460  return playCompleted;
2461 }
2462 
2463 void PlaybackBox::RemoveProgram( uint recordingID, bool forgetHistory,
2464  bool forceMetadataDelete)
2465 {
2466  ProgramInfo *delItem = FindProgramInUILists(recordingID);
2467 
2468  if (!delItem)
2469  return;
2470 
2471  if (!forceMetadataDelete &&
2472  ((delItem->GetAvailableStatus() == asPendingDelete) ||
2473  !delItem->QueryIsDeleteCandidate()))
2474  {
2475  return;
2476  }
2477 
2478  if (m_playList.contains(delItem->GetRecordingID()))
2479  togglePlayListItem(delItem);
2480 
2481  if (!forceMetadataDelete)
2482  delItem->UpdateLastDelete(true);
2483 
2484  delItem->SetAvailableStatus(asPendingDelete, "RemoveProgram");
2486  forceMetadataDelete, forgetHistory);
2487 
2488  // if the item is in the current recording list UI then delete it.
2489  MythUIButtonListItem *uiItem =
2490  m_recordingList->GetItemByData(QVariant::fromValue(delItem));
2491  if (uiItem)
2492  m_recordingList->RemoveItem(uiItem);
2493 }
2494 
2496 {
2497  m_artImage[kArtworkFanart]->Load();
2498 }
2499 
2501 {
2502  m_artImage[kArtworkBanner]->Load();
2503 }
2504 
2506 {
2507  m_artImage[kArtworkCoverart]->Load();
2508 }
2509 
2511 {
2512  QString label;
2513  switch (type)
2514  {
2515  case kDeleteRecording:
2516  label = tr("Are you sure you want to delete:"); break;
2517  case kForceDeleteRecording:
2518  label = tr("Recording file does not exist.\n"
2519  "Are you sure you want to delete:");
2520  break;
2521  case kStopRecording:
2522  label = tr("Are you sure you want to stop:"); break;
2523  }
2524 
2525  ProgramInfo *delItem = nullptr;
2526  if (m_delList.empty())
2527  {
2528  delItem = GetCurrentProgram();
2529  if (delItem != nullptr)
2530  push_onto_del(m_delList, *delItem);
2531  }
2532  else if (m_delList.size() >= 3)
2533  {
2534  delItem = FindProgramInUILists(m_delList[0].toUInt());
2535  }
2536 
2537  if (!delItem)
2538  return;
2539 
2540  uint other_delete_cnt = (m_delList.size() / 3) - 1;
2541 
2542  label += CreateProgramInfoString(*delItem);
2543 
2544  m_popupMenu = new MythMenu(label, this, "deletemenu");
2545 
2546  if ((kDeleteRecording == type) &&
2547  delItem->GetRecordingGroup() != "Deleted" &&
2548  delItem->GetRecordingGroup() != "LiveTV")
2549  {
2550  m_popupMenu->AddItem(tr("Yes, and allow re-record"),
2552  }
2553 
2554  bool defaultIsYes =
2555  ((kDeleteRecording != type) &&
2556  (kForceDeleteRecording != type) &&
2557  (delItem->QueryAutoExpire() != kDisableAutoExpire));
2558 
2559  switch (type)
2560  {
2561  case kDeleteRecording:
2562  m_popupMenu->AddItem(tr("Yes, delete it"),
2563  qOverload<>(&PlaybackBox::Delete), nullptr, defaultIsYes);
2564  break;
2565  case kForceDeleteRecording:
2566  m_popupMenu->AddItem(tr("Yes, delete it"),
2567  &PlaybackBox::DeleteForce, nullptr, defaultIsYes);
2568  break;
2569  case kStopRecording:
2570  m_popupMenu->AddItem(tr("Yes, stop recording"),
2571  &PlaybackBox::StopSelected, nullptr, defaultIsYes);
2572  break;
2573  }
2574 
2575 
2576  if ((kForceDeleteRecording == type) && other_delete_cnt)
2577  {
2579  tr("Yes, delete it and the remaining %1 list items")
2580  .arg(other_delete_cnt), &PlaybackBox::DeleteForceAllRemaining);
2581  }
2582 
2583  switch (type)
2584  {
2585  case kDeleteRecording:
2586  case kForceDeleteRecording:
2587  m_popupMenu->AddItem(tr("No, keep it"), &PlaybackBox::DeleteIgnore,
2588  nullptr, !defaultIsYes);
2589  break;
2590  case kStopRecording:
2591  m_popupMenu->AddItem(tr("No, continue recording"), &PlaybackBox::DeleteIgnore,
2592  nullptr, !defaultIsYes);
2593  break;
2594  }
2595 
2596  if ((type == kForceDeleteRecording) && other_delete_cnt)
2597  {
2599  tr("No, and keep the remaining %1 list items")
2600  .arg(other_delete_cnt),
2602  }
2603 
2604  DisplayPopupMenu();
2605 }
2606 
2608 {
2609  QString msg = pginfo.toString(ProgramInfo::kTitleSubtitle, " ");
2610  msg += "\n";
2611 
2612  QString byWho;
2613  switch (pginfo.GetAvailableStatus())
2614  {
2615  case asAvailable:
2616  if (pginfo.QueryIsInUse(byWho))
2617  {
2618  ShowNotification(tr("Recording Available\n"),
2619  sLocation, msg +
2620  tr("This recording is currently in "
2621  "use by:") + "\n" + byWho);
2622  }
2623  else
2624  {
2625  ShowNotification(tr("Recording Available\n"),
2626  sLocation, msg +
2627  tr("This recording is currently "
2628  "Available"));
2629  }
2630  break;
2631  case asPendingDelete:
2632  ShowNotificationError(tr("Recording Unavailable\n"),
2633  sLocation, msg +
2634  tr("This recording is currently being "
2635  "deleted and is unavailable"));
2636  break;
2637  case asDeleted:
2638  ShowNotificationError(tr("Recording Unavailable\n"),
2639  sLocation, msg +
2640  tr("This recording has been "
2641  "deleted and is unavailable"));
2642  break;
2643  case asFileNotFound:
2644  ShowNotificationError(tr("Recording Unavailable\n"),
2645  sLocation, msg +
2646  tr("The file for this recording can "
2647  "not be found"));
2648  break;
2649  case asZeroByte:
2650  ShowNotificationError(tr("Recording Unavailable\n"),
2651  sLocation, msg +
2652  tr("The file for this recording is "
2653  "empty."));
2654  break;
2655  case asNotYetAvailable:
2656  ShowNotificationError(tr("Recording Unavailable\n"),
2657  sLocation, msg +
2658  tr("This recording is not yet "
2659  "available."));
2660  }
2661 }
2662 
2664 {
2665  QString label = tr("There is %n item(s) in the playlist. Actions affect "
2666  "all items in the playlist", "", m_playList.size());
2667 
2668  auto *menu = new MythMenu(label, this, "slotmenu");
2669 
2670  menu->AddItem(tr("Play"), &PlaybackBox::doPlayList);
2671  menu->AddItem(tr("Shuffle Play"), &PlaybackBox::doPlayListRandom);
2672  menu->AddItem(tr("Clear Playlist"), &PlaybackBox::doClearPlaylist);
2673 
2674  if (GetFocusWidget() == m_groupList)
2675  {
2676  if ((m_viewMask & VIEW_TITLES))
2677  {
2678  menu->AddItem(tr("Toggle playlist for this Category/Title"),
2680  }
2681  else
2682  {
2683  menu->AddItem(tr("Toggle playlist for this Group"),
2685  }
2686  }
2687  else
2688  {
2689  menu->AddItem(tr("Toggle playlist for this recording"),
2690  qOverload<>(&PlaybackBox::togglePlayListItem));
2691  }
2692 
2693  menu->AddItem(tr("Storage Options"), nullptr, createPlaylistStorageMenu());
2694  menu->AddItem(tr("Job Options"), nullptr, createPlaylistJobMenu());
2695  menu->AddItem(tr("Delete"), &PlaybackBox::PlaylistDeleteKeepHistory);
2696  menu->AddItem(tr("Delete, and allow re-record"),
2698 
2699  return menu;
2700 }
2701 
2703 {
2704  QString label = tr("There is %n item(s) in the playlist. Actions affect "
2705  "all items in the playlist", "", m_playList.size());
2706 
2707  auto *menu = new MythMenu(label, this, "slotmenu");
2708 
2709  menu->AddItem(tr("Change Recording Group"), &PlaybackBox::ShowRecGroupChangerUsePlaylist);
2710  menu->AddItem(tr("Change Playback Group"), &PlaybackBox::ShowPlayGroupChangerUsePlaylist);
2711  menu->AddItem(tr("Disable Auto Expire"), &PlaybackBox::doPlaylistExpireSetOff);
2712  menu->AddItem(tr("Enable Auto Expire"), &PlaybackBox::doPlaylistExpireSetOn);
2713  menu->AddItem(tr("Mark as Watched"), &PlaybackBox::doPlaylistWatchedSetOn);
2714  menu->AddItem(tr("Mark as Unwatched"), &PlaybackBox::doPlaylistWatchedSetOff);
2715  menu->AddItem(tr("Allow Re-record"), &PlaybackBox::doPlaylistAllowRerecord);
2716 
2717  return menu;
2718 }
2719 
2721 {
2722  QString label = tr("There is %n item(s) in the playlist. Actions affect "
2723  "all items in the playlist", "", m_playList.size());
2724 
2725  auto *menu = new MythMenu(label, this, "slotmenu");
2726 
2727  QString jobTitle;
2728  QString command;
2729  QList<uint>::Iterator it;
2730  bool isTranscoding = true;
2731  bool isFlagging = true;
2732  bool isMetadataLookup = true;
2733  bool isRunningUserJob1 = true;
2734  bool isRunningUserJob2 = true;
2735  bool isRunningUserJob3 = true;
2736  bool isRunningUserJob4 = true;
2737 
2738  for(it = m_playList.begin(); it != m_playList.end(); ++it)
2739  {
2740  ProgramInfo *tmpItem = FindProgramInUILists(*it);
2741  if (tmpItem)
2742  {
2744  JOB_TRANSCODE,
2745  tmpItem->GetChanID(), tmpItem->GetRecordingStartTime()))
2746  isTranscoding = false;
2748  JOB_COMMFLAG,
2749  tmpItem->GetChanID(), tmpItem->GetRecordingStartTime()))
2750  isFlagging = false;
2752  JOB_METADATA,
2753  tmpItem->GetChanID(), tmpItem->GetRecordingStartTime()))
2754  isMetadataLookup = false;
2756  JOB_USERJOB1,
2757  tmpItem->GetChanID(), tmpItem->GetRecordingStartTime()))
2758  isRunningUserJob1 = false;
2760  JOB_USERJOB2,
2761  tmpItem->GetChanID(), tmpItem->GetRecordingStartTime()))
2762  isRunningUserJob2 = false;
2764  JOB_USERJOB3,
2765  tmpItem->GetChanID(), tmpItem->GetRecordingStartTime()))
2766  isRunningUserJob3 = false;
2768  JOB_USERJOB4,
2769  tmpItem->GetChanID(), tmpItem->GetRecordingStartTime()))
2770  isRunningUserJob4 = false;
2771  if (!isTranscoding && !isFlagging && !isRunningUserJob1 &&
2772  !isRunningUserJob2 && !isRunningUserJob3 && !isRunningUserJob4)
2773  break;
2774  }
2775  }
2776 
2777  if (!isTranscoding)
2778  menu->AddItem(tr("Begin Transcoding"), &PlaybackBox::doPlaylistBeginTranscoding);
2779  else
2780  menu->AddItem(tr("Stop Transcoding"), &PlaybackBox::stopPlaylistTranscoding);
2781 
2782  if (!isFlagging)
2783  menu->AddItem(tr("Begin Commercial Detection"), &PlaybackBox::doPlaylistBeginFlagging);
2784  else
2785  menu->AddItem(tr("Stop Commercial Detection"), &PlaybackBox::stopPlaylistFlagging);
2786 
2787  if (!isMetadataLookup)
2788  menu->AddItem(tr("Begin Metadata Lookup"), &PlaybackBox::doPlaylistBeginLookup);
2789  else
2790  menu->AddItem(tr("Stop Metadata Lookup"), &PlaybackBox::stopPlaylistLookup);
2791 
2792  command = gCoreContext->GetSetting("UserJob1", "");
2793  if (!command.isEmpty())
2794  {
2795  jobTitle = gCoreContext->GetSetting("UserJobDesc1");
2796 
2797  if (!isRunningUserJob1)
2798  {
2799  menu->AddItem(tr("Begin") + ' ' + jobTitle,
2801  }
2802  else
2803  {
2804  menu->AddItem(tr("Stop") + ' ' + jobTitle,
2806  }
2807  }
2808 
2809  command = gCoreContext->GetSetting("UserJob2", "");
2810  if (!command.isEmpty())
2811  {
2812  jobTitle = gCoreContext->GetSetting("UserJobDesc2");
2813 
2814  if (!isRunningUserJob2)
2815  {
2816  menu->AddItem(tr("Begin") + ' ' + jobTitle,
2818  }
2819  else
2820  {
2821  menu->AddItem(tr("Stop") + ' ' + jobTitle,
2823  }
2824  }
2825 
2826  command = gCoreContext->GetSetting("UserJob3", "");
2827  if (!command.isEmpty())
2828  {
2829  jobTitle = gCoreContext->GetSetting("UserJobDesc3");
2830 
2831  if (!isRunningUserJob3)
2832  {
2833  menu->AddItem(tr("Begin") + ' ' + jobTitle,
2835  }
2836  else
2837  {
2838  menu->AddItem(tr("Stop") + ' ' + jobTitle,
2840  }
2841  }
2842 
2843  command = gCoreContext->GetSetting("UserJob4", "");
2844  if (!command.isEmpty())
2845  {
2846  jobTitle = gCoreContext->GetSetting("UserJobDesc4");
2847 
2848  if (!isRunningUserJob4)
2849  {
2850  menu->AddItem(QString("%1 %2").arg(tr("Begin"), jobTitle),
2852  }
2853  else
2854  {
2855  menu->AddItem(QString("%1 %2").arg(tr("Stop"), jobTitle),
2857  }
2858  }
2859 
2860  return menu;
2861 }
2862 
2864 {
2865  if (m_menuDialog || !m_popupMenu)
2866  return;
2867 
2868  m_menuDialog = new MythDialogBox(m_popupMenu, m_popupStack, "pbbmainmenupopup");
2869 
2870  if (m_menuDialog->Create())
2871  {
2874  }
2875  else
2876  {
2877  delete m_menuDialog;
2878  }
2879 }
2880 
2882 {
2883  if (m_menuDialog)
2884  return;
2885 
2886  if (GetFocusWidget() == m_groupList)
2887  ShowGroupPopup();
2888  else
2889  {
2890  ProgramInfo *pginfo = GetCurrentProgram();
2891  if (pginfo)
2892  {
2894  *pginfo, kCheckForMenuAction);
2895 
2896  if ((asPendingDelete == pginfo->GetAvailableStatus()) ||
2897  (asDeleted == pginfo->GetAvailableStatus()) ||
2898  (asNotYetAvailable == pginfo->GetAvailableStatus()))
2899  {
2900  ShowAvailabilityPopup(*pginfo);
2901  }
2902  else
2903  {
2904  ShowActionPopup(*pginfo);
2905  }
2906  }
2907  else
2908  {
2909  ShowGroupPopup();
2910  }
2911  }
2912 }
2913 
2915 {
2916  ProgramInfo *pginfo = GetCurrentProgram();
2917  if (!pginfo)
2918  return nullptr;
2919 
2920  QString title = tr("Play Options") + CreateProgramInfoString(*pginfo);
2921 
2922  auto *menu = new MythMenu(title, this, "slotmenu");
2923  bool hasLastPlay = pginfo->IsLastPlaySet();
2924  bool hasBookMark = pginfo->IsBookmarkSet();
2925  if (hasLastPlay)
2926  menu->AddItem(tr("Play from last played position"),
2927  qOverload<>(&PlaybackBox::PlayFromLastPlayPos));
2928  if (hasBookMark)
2929  menu->AddItem(tr("Play from bookmark"),
2930  qOverload<>(&PlaybackBox::PlayFromBookmark));
2931  menu->AddItem(tr("Play from beginning"),
2932  qOverload<>(&PlaybackBox::PlayFromBeginning));
2933  if (hasLastPlay)
2934  menu->AddItem(tr("Clear last played position"),
2936  if (hasBookMark)
2937  menu->AddItem(tr("Clear bookmark"), &PlaybackBox::ClearBookmark);
2938 
2939  return menu;
2940 }
2941 
2943 {
2944  ProgramInfo *pginfo = GetCurrentProgram();
2945  if (!pginfo)
2946  return nullptr;
2947 
2948  QString title = tr("Storage Options") + CreateProgramInfoString(*pginfo);
2949  QString autoExpireText = (pginfo->IsAutoExpirable()) ?
2950  tr("Disable Auto Expire") : tr("Enable Auto Expire");
2951  QString preserveText = (pginfo->IsPreserved()) ?
2952  tr("Do not preserve this episode") : tr("Preserve this episode");
2953 
2954  auto *menu = new MythMenu(title, this, "slotmenu");
2955  menu->AddItem(tr("Change Recording Group"), &PlaybackBox::ShowRecGroupChangerNoPlaylist);
2956  menu->AddItem(tr("Change Playback Group"), &PlaybackBox::ShowPlayGroupChangerNoPlaylist);
2957  menu->AddItem(autoExpireText, &PlaybackBox::toggleAutoExpire);
2958  menu->AddItem(preserveText, &PlaybackBox::togglePreserveEpisode);
2959 
2960  return menu;
2961 }
2962 
2964 {
2965  ProgramInfo *pginfo = GetCurrentProgram();
2966  if (!pginfo)
2967  return nullptr;
2968 
2969  QString title = tr("Scheduling Options") + CreateProgramInfoString(*pginfo);
2970 
2971  auto *menu = new MythMenu(title, this, "slotmenu");
2972 
2973  menu->AddItem(tr("Edit Recording Schedule"),
2974  qOverload<>(&PlaybackBox::EditScheduled));
2975 
2976  menu->AddItem(tr("Allow this episode to re-record"), &PlaybackBox::doAllowRerecord);
2977 
2978  menu->AddItem(tr("Show Recording Details"), &PlaybackBox::ShowDetails);
2979 
2980  menu->AddItem(tr("Change Recording Metadata"), &PlaybackBox::showMetadataEditor);
2981 
2982  menu->AddItem(tr("Custom Edit"), &PlaybackBox::EditCustom);
2983 
2984  return menu;
2985 }
2986 
2987 static const std::array<const int,kMaxJobs> kJobs
2989  JOB_TRANSCODE,
2990  JOB_COMMFLAG,
2991  JOB_METADATA,
2992  JOB_USERJOB1,
2993  JOB_USERJOB2,
2994  JOB_USERJOB3,
2995  JOB_USERJOB4,
2996 };
2997 std::array<PlaybackBoxCb,kMaxJobs*2> PlaybackBox::kMySlots
2998 { // stop start
3006 };
3007 
3009 {
3010  ProgramInfo *pginfo = GetCurrentProgram();
3011  if (!pginfo)
3012  return nullptr;
3013 
3014  QString title = tr("Job Options") + CreateProgramInfoString(*pginfo);
3015 
3016  auto *menu = new MythMenu(title, this, "slotmenu");
3017 
3018  const std::array<const bool,kMaxJobs> add
3019  {
3020  true,
3021  true,
3022  true,
3023  !gCoreContext->GetSetting("UserJob1", "").isEmpty(),
3024  !gCoreContext->GetSetting("UserJob2", "").isEmpty(),
3025  !gCoreContext->GetSetting("UserJob3", "").isEmpty(),
3026  !gCoreContext->GetSetting("UserJob4", "").isEmpty(),
3027  };
3028  const std::array<const QString,kMaxJobs*2> desc
3029  {
3030  // stop start
3031  tr("Stop Transcoding"), tr("Begin Transcoding"),
3032  tr("Stop Commercial Detection"), tr("Begin Commercial Detection"),
3033  tr("Stop Metadata Lookup"), tr("Begin Metadata Lookup"),
3034  "1", "1",
3035  "2", "2",
3036  "3", "3",
3037  "4", "4",
3038  };
3039 
3040  for (size_t i = 0; i < kMaxJobs; i++)
3041  {
3042  if (!add[i])
3043  continue;
3044 
3045  QString stop_desc = desc[(i*2)+0];
3046  QString start_desc = desc[(i*2)+1];
3047 
3048  if (start_desc.toUInt())
3049  {
3050  QString jobTitle = gCoreContext->GetSetting(
3051  "UserJobDesc"+start_desc, tr("User Job") + " #" + start_desc);
3052  stop_desc = tr("Stop") + ' ' + jobTitle;
3053  start_desc = tr("Begin") + ' ' + jobTitle;
3054  }
3055 
3056  bool running = JobQueue::IsJobQueuedOrRunning(
3057  kJobs[i], pginfo->GetChanID(), pginfo->GetRecordingStartTime());
3058 
3059  MythMenu *submenu = ((kJobs[i] == JOB_TRANSCODE) && !running)
3060  ? createTranscodingProfilesMenu() : nullptr;
3061  menu->AddItem((running) ? stop_desc : start_desc,
3062  kMySlots[(i * 2) + (running ? 0 : 1)], submenu);
3063  }
3064 
3065  return menu;
3066 }
3067 
3069 {
3070  QString label = tr("Transcoding profiles");
3071 
3072  auto *menu = new MythMenu(label, this, "transcode");
3073 
3074  menu->AddItemV(tr("Default"), QVariant::fromValue(-1));
3075  menu->AddItemV(tr("Autodetect"), QVariant::fromValue(0));
3076 
3077  MSqlQuery query(MSqlQuery::InitCon());
3078  query.prepare("SELECT r.name, r.id "
3079  "FROM recordingprofiles r, profilegroups p "
3080  "WHERE p.name = 'Transcoders' "
3081  "AND r.profilegroup = p.id "
3082  "AND r.name != 'RTjpeg/MPEG4' "
3083  "AND r.name != 'MPEG2' ");
3084 
3085  if (!query.exec())
3086  {
3087  MythDB::DBError(LOC + "unable to query transcoders", query);
3088  return nullptr;
3089  }
3090 
3091  while (query.next())
3092  {
3093  QString transcoder_name = query.value(0).toString();
3094  int transcoder_id = query.value(1).toInt();
3095 
3096  // Translatable strings for known profiles
3097  if (transcoder_name == "High Quality")
3098  transcoder_name = tr("High Quality");
3099  else if (transcoder_name == "Medium Quality")
3100  transcoder_name = tr("Medium Quality");
3101  else if (transcoder_name == "Low Quality")
3102  transcoder_name = tr("Low Quality");
3103 
3104  menu->AddItemV(transcoder_name, QVariant::fromValue(transcoder_id));
3105  }
3106 
3107  return menu;
3108 }
3109 
3111 {
3112  ProgramInfo *pginfo = GetCurrentProgram();
3113 
3114  if (!pginfo)
3115  return;
3116 
3117  if (id >= 0)
3118  {
3119  RecordingInfo ri(*pginfo);
3121  }
3123 }
3124 
3126 {
3127  QString label;
3128  if (asFileNotFound == pginfo.GetAvailableStatus())
3129  label = tr("Recording file cannot be found");
3130  else if (asZeroByte == pginfo.GetAvailableStatus())
3131  label = tr("Recording file contains no data");
3132  else
3133  tr("Recording Options");
3134 
3135  m_popupMenu = new MythMenu(label + CreateProgramInfoString(pginfo), this, "actionmenu");
3136 
3137  if ((asFileNotFound == pginfo.GetAvailableStatus()) ||
3138  (asZeroByte == pginfo.GetAvailableStatus()))
3139  {
3140  if (m_playList.contains(pginfo.GetRecordingID()))
3141  {
3142  m_popupMenu->AddItem(tr("Remove from Playlist"),
3143  qOverload<>(&PlaybackBox::togglePlayListItem));
3144  }
3145  else
3146  {
3147  m_popupMenu->AddItem(tr("Add to Playlist"),
3148  qOverload<>(&PlaybackBox::togglePlayListItem));
3149  }
3150 
3151  if (!m_playList.isEmpty())
3152  m_popupMenu->AddItem(tr("Playlist Options"), nullptr, createPlaylistMenu());
3153 
3154  m_popupMenu->AddItem(tr("Recording Options"), nullptr, createRecordingMenu());
3155 
3158  {
3159  m_popupMenu->AddItem(tr("List Recorded Episodes"),
3161  }
3162  else
3163  {
3164  m_popupMenu->AddItem(tr("List All Recordings"),
3166  }
3167 
3168  m_popupMenu->AddItem(tr("Delete"), &PlaybackBox::askDelete);
3169 
3170  DisplayPopupMenu();
3171 
3172  return;
3173  }
3174 
3175  bool sameProgram = false;
3176 
3177  if (m_player)
3178  sameProgram = m_player->IsSameProgram(&pginfo);
3179 
3180  TVState tvstate = kState_None;
3181 
3182  if (!sameProgram)
3183  {
3184  if (pginfo.IsBookmarkSet() || pginfo.IsLastPlaySet())
3185  m_popupMenu->AddItem(tr("Play from..."), nullptr, createPlayFromMenu());
3186  else
3187  m_popupMenu->AddItem(tr("Play"),
3188  qOverload<>(&PlaybackBox::PlayFromAnyMark));
3189  }
3190 
3191  if (!m_player)
3192  {
3193  if (m_playList.contains(pginfo.GetRecordingID()))
3194  {
3195  m_popupMenu->AddItem(tr("Remove from Playlist"),
3196  qOverload<>(&PlaybackBox::togglePlayListItem));
3197  }
3198  else
3199  {
3200  m_popupMenu->AddItem(tr("Add to Playlist"),
3201  qOverload<>(&PlaybackBox::togglePlayListItem));
3202  }
3203  if (!m_playList.isEmpty())
3204  {
3205  m_popupMenu->AddItem(tr("Playlist Options"), nullptr, createPlaylistMenu());
3206  }
3207  }
3208 
3209  if ((pginfo.GetRecordingStatus() == RecStatus::Recording ||
3210  pginfo.GetRecordingStatus() == RecStatus::Tuning ||
3211  pginfo.GetRecordingStatus() == RecStatus::Failing) &&
3212  (!sameProgram ||
3213  (tvstate != kState_WatchingLiveTV &&
3214  tvstate != kState_WatchingRecording)))
3215  {
3216  m_popupMenu->AddItem(tr("Stop Recording"), &PlaybackBox::askStop);
3217  }
3218 
3219  if (pginfo.IsWatched())
3220  m_popupMenu->AddItem(tr("Mark as Unwatched"), &PlaybackBox::toggleWatched);
3221  else
3222  m_popupMenu->AddItem(tr("Mark as Watched"), &PlaybackBox::toggleWatched);
3223 
3224  m_popupMenu->AddItem(tr("Storage Options"), nullptr, createStorageMenu());
3225  m_popupMenu->AddItem(tr("Recording Options"), nullptr, createRecordingMenu());
3226  m_popupMenu->AddItem(tr("Job Options"), nullptr, createJobMenu());
3227 
3230  {
3231  m_popupMenu->AddItem(tr("List Recorded Episodes"),
3233  }
3234  else
3235  {
3236  m_popupMenu->AddItem(tr("List All Recordings"),
3238  }
3239 
3240  if (!sameProgram)
3241  {
3242  if (pginfo.GetRecordingGroup() == "Deleted")
3243  {
3244  push_onto_del(m_delList, pginfo);
3245  m_popupMenu->AddItem(tr("Undelete"), &PlaybackBox::Undelete);
3246  m_popupMenu->AddItem(tr("Delete Forever"), qOverload<>(&PlaybackBox::Delete));
3247  }
3248  else
3249  {
3250  m_popupMenu->AddItem(tr("Delete"), &PlaybackBox::askDelete);
3251  }
3252  }
3253 
3254  DisplayPopupMenu();
3255 }
3256 
3258 {
3259  QDateTime recstartts = pginfo.GetRecordingStartTime();
3260  QDateTime recendts = pginfo.GetRecordingEndTime();
3261 
3262  QString timedate = QString("%1 - %2")
3263  .arg(MythDate::toString(
3265  MythDate::toString(recendts, MythDate::kTime));
3266 
3267  QString title = pginfo.GetTitle();
3268 
3269  QString extra;
3270 
3271  if (!pginfo.GetSubtitle().isEmpty())
3272  {
3273  extra = QString('\n') + pginfo.GetSubtitle();
3274  }
3275 
3276  return QString("\n%1%2\n%3").arg(title, extra, timedate);
3277 }
3278 
3280 {
3281  QList<uint>::Iterator it;
3282  for (it = m_playList.begin(); it != m_playList.end(); ++it)
3283  {
3284  ProgramInfo *tmpItem = FindProgramInUILists(*it);
3285 
3286  if (!tmpItem)
3287  continue;
3288 
3289  MythUIButtonListItem *item =
3290  m_recordingList->GetItemByData(QVariant::fromValue(tmpItem));
3291 
3292  if (item)
3293  item->DisplayState("no", "playlist");
3294  }
3295  m_playList.clear();
3296 }
3297 
3299 {
3300  playSelectedPlaylist(false);
3301 }
3302 
3303 
3305 {
3306  playSelectedPlaylist(true);
3307 }
3308 
3310 {
3311  ProgramInfo *pginfo = GetCurrentProgram();
3312  if (pginfo)
3313  {
3314  push_onto_del(m_delList, *pginfo);
3316  }
3317 }
3318 
3326 {
3327  ProgramInfo *pginfo = GetCurrentProgram();
3328 
3329  if (!pginfo)
3330  return;
3331 
3332  RecordingInfo ri(*pginfo);
3333  ri.ForgetHistory();
3334  *pginfo = ri;
3335 }
3336 
3338 {
3339  QList<uint>::Iterator it;
3340 
3341  for (it = m_playList.begin(); it != m_playList.end(); ++it)
3342  {
3343  ProgramInfo *pginfo = FindProgramInUILists(*it);
3344  if (pginfo != nullptr)
3345  {
3346  RecordingInfo ri(*pginfo);
3347  ri.ForgetHistory();
3348  *pginfo = ri;
3349  }
3350  }
3351 
3352  doClearPlaylist();
3353  UpdateUILists();
3354 }
3355 
3356 void PlaybackBox::doJobQueueJob(int jobType, int jobFlags)
3357 {
3358  ProgramInfo *pginfo = GetCurrentProgram();
3359 
3360  if (!pginfo)
3361  return;
3362 
3363  ProgramInfo *tmpItem = FindProgramInUILists(*pginfo);
3364 
3366  jobType, pginfo->GetChanID(), pginfo->GetRecordingStartTime()))
3367  {
3369  jobType, pginfo->GetChanID(), pginfo->GetRecordingStartTime(),
3370  JOB_STOP);
3371  if ((jobType & JOB_COMMFLAG) && (tmpItem))
3372  {
3373  tmpItem->SetEditing(false);
3374  tmpItem->SetFlagging(false);
3375  }
3376  }
3377  else
3378  {
3379  QString jobHost;
3380  if (gCoreContext->GetBoolSetting("JobsRunOnRecordHost", false))
3381  jobHost = pginfo->GetHostname();
3382 
3383  JobQueue::QueueJob(jobType, pginfo->GetChanID(),
3384  pginfo->GetRecordingStartTime(), "", "", jobHost,
3385  jobFlags);
3386  }
3387 }
3388 
3390 {
3392 }
3393 
3395 {
3397 }
3398 
3399 void PlaybackBox::doPlaylistJobQueueJob(int jobType, int jobFlags)
3400 {
3401  for (const uint pbs : std::as_const(m_playList))
3402  {
3403  ProgramInfo *tmpItem = FindProgramInUILists(pbs);
3404  if (tmpItem &&
3406  jobType,
3407  tmpItem->GetChanID(), tmpItem->GetRecordingStartTime())))
3408  {
3409  QString jobHost;
3410  if (gCoreContext->GetBoolSetting("JobsRunOnRecordHost", false))
3411  jobHost = tmpItem->GetHostname();
3412 
3413  JobQueue::QueueJob(jobType, tmpItem->GetChanID(),
3414  tmpItem->GetRecordingStartTime(),
3415  "", "", jobHost, jobFlags);
3416  }
3417  }
3418 }
3419 
3421 {
3422  QList<uint>::Iterator it;
3423 
3424  for (it = m_playList.begin(); it != m_playList.end(); ++it)
3425  {
3426  ProgramInfo *tmpItem = FindProgramInUILists(*it);
3427  if (tmpItem &&
3429  jobType,
3430  tmpItem->GetChanID(), tmpItem->GetRecordingStartTime())))
3431  {
3433  jobType, tmpItem->GetChanID(),
3434  tmpItem->GetRecordingStartTime(), JOB_STOP);
3435 
3436  if (jobType & JOB_COMMFLAG)
3437  {
3438  tmpItem->SetEditing(false);
3439  tmpItem->SetFlagging(false);
3440  }
3441  }
3442  }
3443 }
3444 
3446 {
3447  ProgramInfo *pginfo = GetCurrentProgram();
3448  if (pginfo)
3449  {
3450  push_onto_del(m_delList, *pginfo);
3452  }
3453 }
3454 
3455 void PlaybackBox::PlaylistDelete(bool forgetHistory)
3456 {
3457  QString forceDeleteStr("0");
3458 
3459  QStringList list;
3460  for (int id : std::as_const(m_playList))
3461  {
3462  ProgramInfo *tmpItem = FindProgramInUILists(id);
3463  if (tmpItem && tmpItem->QueryIsDeleteCandidate())
3464  {
3465  tmpItem->SetAvailableStatus(asPendingDelete, "PlaylistDelete");
3466  list.push_back(QString::number(tmpItem->GetRecordingID()));
3467  list.push_back(forceDeleteStr);
3468  list.push_back(forgetHistory ? "1" : "0");
3469 
3470  // if the item is in the current recording list UI then delete it.
3471  MythUIButtonListItem *uiItem =
3472  m_recordingList->GetItemByData(QVariant::fromValue(tmpItem));
3473  if (uiItem)
3474  m_recordingList->RemoveItem(uiItem);
3475  }
3476  }
3477  m_playList.clear();
3478 
3479  if (!list.empty())
3480  m_helper.DeleteRecordings(list);
3481 
3482  doClearPlaylist();
3483 }
3484 
3485 // FIXME: Huh? This doesn't specify which recording to undelete, it just
3486 // undeletes the first one on the list
3488 {
3489  uint recordingID = 0;
3490  if (extract_one_del(m_delList, recordingID))
3491  m_helper.UndeleteRecording(recordingID);
3492 }
3493 
3495 {
3496  uint recordingID = 0;
3497  while (extract_one_del(m_delList, recordingID))
3498  {
3499  if (flags & kIgnore)
3500  continue;
3501 
3502  RemoveProgram(recordingID, (flags & kForgetHistory) != 0, (flags & kForce) != 0);
3503 
3504  if (!(flags & kAllRemaining))
3505  break;
3506  }
3507 
3508  if (!m_delList.empty())
3509  {
3510  auto *e = new MythEvent("DELETE_FAILURES", m_delList);
3511  m_delList.clear();
3512  QCoreApplication::postEvent(this, e);
3513  }
3514 }
3515 
3517 {
3518  ProgramInfo *pginfo = GetCurrentProgram();
3519  if (pginfo) {
3520  QString title = pginfo->GetTitle().toLower();
3521  MythUIButtonListItem* group = m_groupList->GetItemByData(QVariant::fromValue(title));
3522  if (group)
3523  {
3524  m_groupList->SetItemCurrent(group);
3525  // set focus back to previous item
3526  MythUIButtonListItem *previousItem = m_recordingList->GetItemByData(QVariant::fromValue(pginfo));
3527  m_recordingList->SetItemCurrent(previousItem);
3528  }
3529  }
3530 }
3531 
3533 {
3534  ProgramInfo *pginfo = GetCurrentProgram();
3536  if (pginfo)
3537  {
3538  // set focus back to previous item
3539  MythUIButtonListItem *previousitem =
3540  m_recordingList->GetItemByData(QVariant::fromValue(pginfo));
3541  m_recordingList->SetItemCurrent(previousitem);
3542  }
3543 }
3544 
3546 {
3547  return FindProgramInUILists( pginfo.GetRecordingID(),
3548  pginfo.GetRecordingGroup());
3549 }
3550 
3552  const QString& recgroup)
3553 {
3554  // LiveTV ProgramInfo's are not in the aggregated list
3555  std::array<ProgramList::iterator,2> _it {
3556  m_progLists[tr("Live TV").toLower()].begin(), m_progLists[""].begin() };
3557  std::array<ProgramList::iterator,2> _end {
3558  m_progLists[tr("Live TV").toLower()].end(), m_progLists[""].end() };
3559 
3560  if (recgroup != "LiveTV")
3561  {
3562  swap( _it[0], _it[1]);
3563  swap(_end[0], _end[1]);
3564  }
3565 
3566  for (uint i = 0; i < 2; i++)
3567  {
3568  auto it = _it[i];
3569  const auto& end = _end[i];
3570  for (; it != end; ++it)
3571  {
3572  if ((*it)->GetRecordingID() == recordingID)
3573  {
3574  return *it;
3575  }
3576  }
3577  }
3578 
3579  return nullptr;
3580 }
3581 
3583 {
3585 
3586  if (!item)
3587  return;
3588 
3589  auto *pginfo = item->GetData().value<ProgramInfo *>();
3590 
3591  if (!pginfo)
3592  return;
3593 
3594  bool on = !pginfo->IsWatched();
3595  pginfo->SaveWatched(on);
3596  item->DisplayState((on)?"yes":"on", "watched");
3597  updateIcons(pginfo);
3598 
3599  // A refill affects the responsiveness of the UI and we only
3600  // need to rebuild the list if the watch list is displayed
3601  if (m_viewMask & VIEW_WATCHLIST)
3602  UpdateUILists();
3603 }
3604 
3606 {
3608 
3609  if (!item)
3610  return;
3611 
3612  auto *pginfo = item->GetData().value<ProgramInfo *>();
3613 
3614  if (!pginfo)
3615  return;
3616 
3617  bool on = !pginfo->IsAutoExpirable();
3618  pginfo->SaveAutoExpire((on) ? kNormalAutoExpire : kDisableAutoExpire, true);
3619  item->DisplayState((on)?"yes":"no", "autoexpire");
3620  updateIcons(pginfo);
3621 }
3622 
3624 {
3626 
3627  if (!item)
3628  return;
3629 
3630  auto *pginfo = item->GetData().value<ProgramInfo *>();
3631 
3632  if (!pginfo)
3633  return;
3634 
3635  bool on = !pginfo->IsPreserved();
3636  pginfo->SavePreserve(on);
3637  item->DisplayState(on?"yes":"no", "preserve");
3638  updateIcons(pginfo);
3639 }
3640 
3641 void PlaybackBox::toggleView(ViewMask itemMask, bool setOn)
3642 {
3643  if (setOn)
3644  m_viewMask = (ViewMask)(m_viewMask | itemMask);
3645  else
3646  m_viewMask = (ViewMask)(m_viewMask & ~itemMask);
3647 
3648  UpdateUILists();
3649 }
3650 
3652 {
3653  QString groupname = m_groupList->GetItemCurrent()->GetData().toString();
3654 
3655  for (auto *pl : std::as_const(m_progLists[groupname]))
3656  {
3657  if (pl && (pl->GetAvailableStatus() == asAvailable))
3658  togglePlayListItem(pl);
3659  }
3660 }
3661 
3663 {
3665 
3666  if (!item)
3667  return;
3668 
3669  auto *pginfo = item->GetData().value<ProgramInfo *>();
3670 
3671  if (!pginfo)
3672  return;
3673 
3674  togglePlayListItem(pginfo);
3675 
3678 }
3679 
3681 {
3682  if (!pginfo)
3683  return;
3684 
3685  uint recordingID = pginfo->GetRecordingID();
3686 
3687  MythUIButtonListItem *item =
3688  m_recordingList->GetItemByData(QVariant::fromValue(pginfo));
3689 
3690  if (m_playList.contains(recordingID))
3691  {
3692  if (item)
3693  item->DisplayState("no", "playlist");
3694 
3695  m_playList.removeAll(recordingID);
3696  }
3697  else
3698  {
3699  if (item)
3700  item->DisplayState("yes", "playlist");
3701  m_playList.append(recordingID);
3702  }
3703 }
3704 
3706 {
3707  int commands = 0;
3708  QString command;
3709 
3710  m_ncLock.lock();
3711  commands = m_networkControlCommands.size();
3712  m_ncLock.unlock();
3713 
3714  while (commands)
3715  {
3716  m_ncLock.lock();
3717  command = m_networkControlCommands.front();
3718  m_networkControlCommands.pop_front();
3719  m_ncLock.unlock();
3720 
3722 
3723  m_ncLock.lock();
3724  commands = m_networkControlCommands.size();
3725  m_ncLock.unlock();
3726  }
3727 }
3728 
3729 void PlaybackBox::processNetworkControlCommand(const QString &command)
3730 {
3731  QStringList tokens = command.simplified().split(" ");
3732 
3733  if (tokens.size() >= 4 && (tokens[1] == "PLAY" || tokens[1] == "RESUME"))
3734  {
3735  if (tokens.size() == 6 && tokens[2] == "PROGRAM")
3736  {
3737  int clientID = tokens[5].toInt();
3738 
3739  LOG(VB_GENERAL, LOG_INFO, LOC +
3740  QString("NetworkControl: Trying to %1 program '%2' @ '%3'")
3741  .arg(tokens[1], tokens[3], tokens[4]));
3742 
3743  if (m_playingSomething)
3744  {
3745  LOG(VB_GENERAL, LOG_ERR, LOC +
3746  "NetworkControl: Already playing");
3747 
3748  QString msg = QString(
3749  "NETWORK_CONTROL RESPONSE %1 ERROR: Unable to play, "
3750  "player is already playing another recording.")
3751  .arg(clientID);
3752 
3753  MythEvent me(msg);
3754  gCoreContext->dispatch(me);
3755  return;
3756  }
3757 
3758  uint chanid = tokens[3].toUInt();
3759  QDateTime recstartts = MythDate::fromString(tokens[4]);
3760  ProgramInfo pginfo(chanid, recstartts);
3761 
3762  if (pginfo.GetChanID())
3763  {
3764  QString msg = QString("NETWORK_CONTROL RESPONSE %1 OK")
3765  .arg(clientID);
3766  MythEvent me(msg);
3767  gCoreContext->dispatch(me);
3768 
3769  pginfo.SetPathname(pginfo.GetPlaybackURL());
3770 
3771  const bool ignoreBookmark = (tokens[1] == "PLAY");
3772  const bool ignoreProgStart = true;
3773  const bool ignoreLastPlayPos = true;
3774  const bool underNetworkControl = true;
3775  PlayX(pginfo, ignoreBookmark, ignoreProgStart,
3776  ignoreLastPlayPos, underNetworkControl);
3777  }
3778  else
3779  {
3780  QString message = QString("NETWORK_CONTROL RESPONSE %1 "
3781  "ERROR: Could not find recording for "
3782  "chanid %2 @ %3")
3783  .arg(tokens[5], tokens[3], tokens[4]);
3784  MythEvent me(message);
3785  gCoreContext->dispatch(me);
3786  }
3787  }
3788  }
3789 }
3790 
3791 bool PlaybackBox::keyPressEvent(QKeyEvent *event)
3792 {
3793  // This should be an impossible keypress we've simulated
3794  if ((event->key() == Qt::Key_LaunchMedia) &&
3795  (event->modifiers() ==
3796  (Qt::ShiftModifier |
3797  Qt::ControlModifier |
3798  Qt::AltModifier |
3799  Qt::MetaModifier |
3800  Qt::KeypadModifier)))
3801  {
3802  event->accept();
3803  m_ncLock.lock();
3804  int commands = m_networkControlCommands.size();
3805  m_ncLock.unlock();
3806  if (commands)
3808  return true;
3809  }
3810 
3811  if (GetFocusWidget()->keyPressEvent(event))
3812  return true;
3813 
3814  QStringList actions;
3815  bool handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend",
3816  event, actions);
3817 
3818  for (int i = 0; i < actions.size() && !handled; ++i)
3819  {
3820  const QString& action = actions[i];
3821  handled = true;
3822 
3823  if (action == ACTION_1 || action == "HELP")
3824  showIconHelp();
3825  else if (action == "MENU")
3826  {
3827  ShowMenu();
3828  }
3829  else if (action == "NEXTFAV")
3830  {
3831  if (GetFocusWidget() == m_groupList)
3833  else
3835  }
3836  else if (action == "TOGGLEFAV")
3837  {
3838  m_playList.clear();
3839  UpdateUILists();
3840  }
3841  else if (action == ACTION_TOGGLERECORD)
3842  {
3844  UpdateUILists();
3845  }
3846  else if (action == ACTION_PAGERIGHT)
3847  {
3849  }
3850  else if (action == ACTION_PAGELEFT)
3851  {
3852  QString nextGroup;
3853  m_recGroupsLock.lock();
3854  if (m_recGroupIdx >= 0 && !m_recGroups.empty())
3855  {
3856  if (--m_recGroupIdx < 0)
3857  m_recGroupIdx = m_recGroups.size() - 1;
3858  nextGroup = m_recGroups[m_recGroupIdx];
3859  }
3860  m_recGroupsLock.unlock();
3861 
3862  if (!nextGroup.isEmpty())
3863  displayRecGroup(nextGroup);
3864  }
3865  else if (action == "NEXTVIEW")
3866  {
3868  if (++curpos >= m_groupList->GetCount())
3869  curpos = 0;
3870  m_groupList->SetItemCurrent(curpos);
3871  }
3872  else if (action == "PREVVIEW")
3873  {
3875  if (--curpos < 0)
3876  curpos = m_groupList->GetCount() - 1;
3877  m_groupList->SetItemCurrent(curpos);
3878  }
3879  else if (action == ACTION_LISTRECORDEDEPISODES)
3880  {
3884  else
3886  }
3887  else if (action == "CHANGERECGROUP")
3888  {
3889  showGroupFilter();
3890  }
3891  else if (action == "CHANGEGROUPVIEW")
3892  {
3893  showViewChanger();
3894  }
3895  else if (action == "EDIT")
3896  {
3897  EditScheduled();
3898  }
3899  else if (m_titleList.size() > 1)
3900  {
3901  if (action == "DELETE")
3903  else if (action == ACTION_PLAYBACK)
3904  PlayFromAnyMark();
3905  else if (action == "DETAILS" || action == "INFO")
3906  ShowDetails();
3907  else if (action == "CUSTOMEDIT")
3908  EditCustom();
3909  else if (action == "GUIDE")
3910  ShowGuide();
3911  else if (action == "UPCOMING")
3912  ShowUpcoming();
3913  else if (action == ACTION_VIEWSCHEDULED)
3915  else if (action == ACTION_PREVRECORDED)
3916  ShowPrevious();
3917  else
3918  handled = false;
3919  }
3920  else
3921  {
3922  handled = false;
3923  }
3924  }
3925 
3926  if (!handled && MythScreenType::keyPressEvent(event))
3927  handled = true;
3928 
3929  return handled;
3930 }
3931 
3932 void PlaybackBox::customEvent(QEvent *event)
3933 {
3934  if (event->type() == DialogCompletionEvent::kEventType)
3935  {
3936  auto *dce = dynamic_cast<DialogCompletionEvent*>(event);
3937  if (!dce)
3938  return;
3939 
3940  QString resultid = dce->GetId();
3941 
3942  if (resultid == "transcode" && dce->GetResult() >= 0)
3943  changeProfileAndTranscode(dce->GetData().toInt());
3944  }
3945  else if (event->type() == MythEvent::kMythEventMessage)
3946  {
3947  auto *me = dynamic_cast<MythEvent *>(event);
3948  if (me == nullptr)
3949  return;
3950 
3951  const QString& message = me->Message();
3952 
3953  if (message.startsWith("RECORDING_LIST_CHANGE"))
3954  {
3955  QStringList tokens = message.simplified().split(" ");
3956  uint recordingID = 0;
3957  if (tokens.size() >= 3)
3958  recordingID = tokens[2].toUInt();
3959 
3960  if ((tokens.size() >= 2) && tokens[1] == "UPDATE")
3961  {
3962  ProgramInfo evinfo(me->ExtraDataList());
3963  if (evinfo.HasPathname() || evinfo.GetChanID())
3964  {
3965  uint32_t flags = m_programInfoCache.Update(evinfo);
3966  if (flags != ProgramInfoCache::PIC_NO_ACTION)
3967  HandleUpdateItemEvent(evinfo.GetRecordingID(), flags);
3968  }
3969  }
3970  else if (recordingID && (tokens[1] == "ADD"))
3971  {
3972  ProgramInfo evinfo(recordingID);
3973  if (evinfo.GetChanID())
3974  {
3976  HandleRecordingAddEvent(evinfo);
3977  }
3978  }
3979  else if (recordingID && (tokens[1] == "DELETE"))
3980  {
3981  HandleRecordingRemoveEvent(recordingID);
3982  }
3983  else
3984  {
3986  }
3987  }
3988  else if (message.startsWith("NETWORK_CONTROL"))
3989  {
3990  QStringList tokens = message.simplified().split(" ");
3991  if ((tokens[1] != "ANSWER") && (tokens[1] != "RESPONSE"))
3992  {
3993  m_ncLock.lock();
3994  m_networkControlCommands.push_back(message);
3995  m_ncLock.unlock();
3996 
3997  // This should be an impossible keypress we're simulating
3998  Qt::KeyboardModifiers modifiers =
3999  Qt::ShiftModifier |
4000  Qt::ControlModifier |
4001  Qt::AltModifier |
4002  Qt::MetaModifier |
4003  Qt::KeypadModifier;
4004  auto *keyevent = new QKeyEvent(QEvent::KeyPress,
4005  Qt::Key_LaunchMedia, modifiers);
4006  QCoreApplication::postEvent(GetMythMainWindow(), keyevent);
4007 
4008  keyevent = new QKeyEvent(QEvent::KeyRelease,
4009  Qt::Key_LaunchMedia, modifiers);
4010  QCoreApplication::postEvent(GetMythMainWindow(), keyevent);
4011  }
4012  }
4013  else if (message.startsWith("UPDATE_FILE_SIZE"))
4014  {
4015  QStringList tokens = message.simplified().split(" ");
4016  if (tokens.size() >= 3)
4017  {
4018  bool ok = false;
4019  uint recordingID = tokens[1].toUInt();
4020  uint64_t filesize = tokens[2].toLongLong(&ok);
4021  if (ok)
4022  {
4023  // Delegate to background thread
4024  MConcurrent::run("UpdateFileSize", &m_programInfoCache,
4026  recordingID, filesize,
4028  }
4029  }
4030  }
4031  else if (message == "UPDATE_UI_LIST")
4032  {
4033  if (m_playingSomething)
4034  m_needUpdate = true;
4035  else
4036  {
4037  UpdateUILists();
4039  }
4040  }
4041  else if (message.startsWith("UPDATE_UI_ITEM"))
4042  {
4043  QStringList tokens = message.simplified().split(" ");
4044  if (tokens.size() < 3)
4045  return;
4046 
4047  uint recordingID = tokens[1].toUInt();
4048  auto flags = static_cast<ProgramInfoCache::UpdateState>(tokens[2].toUInt());
4049 
4050  if (flags != ProgramInfoCache::PIC_NO_ACTION)
4051  HandleUpdateItemEvent(recordingID, flags);
4052  }
4053  else if (message == "UPDATE_USAGE_UI")
4054  {
4055  UpdateUsageUI();
4056  }
4057  else if (message == "RECONNECT_SUCCESS")
4058  {
4060  }
4061  else if (message == "LOCAL_PBB_DELETE_RECORDINGS")
4062  {
4063  QStringList list;
4064  for (uint i = 0; i+2 < (uint)me->ExtraDataList().size(); i+=3)
4065  {
4066  uint recordingID = me->ExtraDataList()[i+0].toUInt();
4067  ProgramInfo *pginfo =
4068  m_programInfoCache.GetRecordingInfo(recordingID);
4069 
4070  if (!pginfo)
4071  {
4072  LOG(VB_GENERAL, LOG_WARNING, LOC +
4073  QString("LOCAL_PBB_DELETE_RECORDINGS - "
4074  "No matching recording %1")
4075  .arg(recordingID));
4076  continue;
4077  }
4078 
4079  QString forceDeleteStr = me->ExtraDataList()[i+1];
4080  QString forgetHistoryStr = me->ExtraDataList()[i+2];
4081 
4082  list.push_back(QString::number(pginfo->GetRecordingID()));
4083  list.push_back(forceDeleteStr);
4084  list.push_back(forgetHistoryStr);
4086  "LOCAL_PBB_DELETE_RECORDINGS");
4087 
4088  // if the item is in the current recording list UI
4089  // then delete it.
4090  MythUIButtonListItem *uiItem =
4091  m_recordingList->GetItemByData(QVariant::fromValue(pginfo));
4092  if (uiItem)
4093  m_recordingList->RemoveItem(uiItem);
4094  }
4095  if (!list.empty())
4096  m_helper.DeleteRecordings(list);
4097  }
4098  else if (message == "DELETE_SUCCESSES")
4099  {
4101  }
4102  else if (message == "DELETE_FAILURES")
4103  {
4104  if (me->ExtraDataList().size() < 3)
4105  return;
4106 
4107  for (uint i = 0; i+2 < (uint)me->ExtraDataList().size(); i += 3)
4108  {
4110  me->ExtraDataList()[i+0].toUInt());
4111  if (pginfo)
4112  {
4113  pginfo->SetAvailableStatus(asAvailable, "DELETE_FAILURES");
4115  }
4116  }
4117 
4118  bool forceDelete = me->ExtraDataList()[1].toUInt() != 0U;
4119  if (!forceDelete)
4120  {
4121  m_delList = me->ExtraDataList();
4122  if (!m_menuDialog)
4123  {
4125  return;
4126  }
4127  LOG(VB_GENERAL, LOG_WARNING, LOC +
4128  "Delete failures not handled due to "
4129  "pre-existing popup.");
4130  }
4131 
4132  // Since we deleted items from the UI after we set
4133  // asPendingDelete, we need to put them back now..
4135  }
4136  else if (message == "PREVIEW_SUCCESS")
4137  {
4138  HandlePreviewEvent(me->ExtraDataList());
4139  }
4140  else if (message == "PREVIEW_FAILED" && me->ExtraDataCount() >= 5)
4141  {
4142  for (uint i = 4; i < (uint) me->ExtraDataCount(); i++)
4143  {
4144  const QString& token = me->ExtraData(i);
4145  QSet<QString>::iterator it = m_previewTokens.find(token);
4146  if (it != m_previewTokens.end())
4147  m_previewTokens.erase(it);
4148  }
4149  }
4150  else if (message == "AVAILABILITY" && me->ExtraDataCount() == 8)
4151  {
4152  static constexpr std::chrono::milliseconds kMaxUIWaitTime = 10s;
4153  QStringList list = me->ExtraDataList();
4154  uint recordingID = list[0].toUInt();
4155  auto cat = (CheckAvailabilityType) list[1].toInt();
4156  auto availableStatus = (AvailableStatusType) list[2].toInt();
4157  uint64_t fs = list[3].toULongLong();
4158  QTime tm;
4159  tm.setHMS(list[4].toUInt(), list[5].toUInt(),
4160  list[6].toUInt(), list[7].toUInt());
4161  QTime now = QTime::currentTime();
4162  auto time_elapsed = std::chrono::milliseconds(tm.msecsTo(now));
4163  if (time_elapsed < 0ms)
4164  time_elapsed += 24h;
4165 
4166  AvailableStatusType old_avail = availableStatus;
4167  ProgramInfo *pginfo = FindProgramInUILists(recordingID);
4168  if (pginfo)
4169  {
4170  pginfo->SetFilesize(std::max(pginfo->GetFilesize(), fs));
4171  old_avail = pginfo->GetAvailableStatus();
4172  pginfo->SetAvailableStatus(availableStatus, "AVAILABILITY");
4173  }
4174 
4175  if (time_elapsed >= kMaxUIWaitTime)
4176  m_playListPlay.clear();
4177 
4178  bool playnext = ((kCheckForPlaylistAction == cat) &&
4179  !m_playListPlay.empty());
4180 
4181 
4182  if (((kCheckForPlayAction == cat) ||
4183  (kCheckForPlaylistAction == cat)) &&
4184  (time_elapsed < kMaxUIWaitTime))
4185  {
4186  if (asAvailable != availableStatus)
4187  {
4188  if (kCheckForPlayAction == cat && pginfo)
4189  ShowAvailabilityPopup(*pginfo);
4190  }
4191  else if (pginfo)
4192  {
4193  playnext = false;
4194  const bool ignoreBookmark = false;
4195  const bool ignoreProgStart = false;
4196  const bool ignoreLastPlayPos = true;
4197  const bool underNetworkControl = false;
4198  Play(*pginfo, kCheckForPlaylistAction == cat,
4199  ignoreBookmark, ignoreProgStart, ignoreLastPlayPos,
4200  underNetworkControl);
4201  }
4202  }
4203 
4204  if (playnext)
4205  {
4206  // failed to play this item, instead
4207  // play the next item on the list..
4208  QCoreApplication::postEvent(
4209  this, new MythEvent("PLAY_PLAYLIST"));
4210  }
4211 
4212  if (old_avail != availableStatus)
4213  UpdateUIListItem(pginfo, true);
4214  }
4215  else if ((message == "PLAY_PLAYLIST") && !m_playListPlay.empty())
4216  {
4217  uint recordingID = m_playListPlay.front();
4218  m_playListPlay.pop_front();
4219 
4220  if (!m_playListPlay.empty())
4221  {
4222  const ProgramInfo *pginfo =
4224  if (pginfo)
4226  }
4227 
4228  ProgramInfo *pginfo = FindProgramInUILists(recordingID);
4229  const bool ignoreBookmark = false;
4230  const bool ignoreProgStart = true;
4231  const bool ignoreLastPlayPos = true;
4232  const bool underNetworkControl = false;
4233  if (pginfo)
4234  Play(*pginfo, true, ignoreBookmark, ignoreProgStart,
4235  ignoreLastPlayPos, underNetworkControl);
4236  }
4237  else if ((message == "SET_PLAYBACK_URL") && (me->ExtraDataCount() == 2))
4238  {
4239  uint recordingID = me->ExtraData(0).toUInt();
4241  if (info)
4242  info->SetPathname(me->ExtraData(1));
4243  }
4244  else if ((message == "FOUND_ARTWORK") && (me->ExtraDataCount() >= 5))
4245  {
4246  auto type = (VideoArtworkType) me->ExtraData(2).toInt();
4247  uint recordingID = me->ExtraData(3).toUInt();
4248  const QString& group = me->ExtraData(4);
4249  const QString& fn = me->ExtraData(5);
4250 
4251  if (recordingID)
4252  {
4253  ProgramInfo *pginfo = m_programInfoCache.GetRecordingInfo(recordingID);
4254  if (pginfo &&
4255  m_recordingList->GetItemByData(QVariant::fromValue(pginfo)) ==
4257  m_artImage[(uint)type]->GetFilename() != fn)
4258  {
4259  m_artImage[(uint)type]->SetFilename(fn);
4260  m_artTimer[(uint)type]->start(s_artDelay[(uint)type]);
4261  }
4262  }
4263  else if (!group.isEmpty() &&
4264  (m_currentGroup == group) &&
4265  m_artImage[type] &&
4267  m_artImage[(uint)type]->GetFilename() != fn)
4268  {
4269  m_artImage[(uint)type]->SetFilename(fn);
4270  m_artTimer[(uint)type]->start(s_artDelay[(uint)type]);
4271  }
4272  }
4273  else if (message == "EXIT_TO_MENU" ||
4274  message == "CANCEL_PLAYLIST")
4275  {
4276  m_playListPlay.clear();
4277  }
4278  }
4279  else
4280  {
4282  }
4283 }
4284 
4286 {
4287  if (!m_programInfoCache.Remove(recordingID))
4288  {
4289  LOG(VB_GENERAL, LOG_WARNING, LOC +
4290  QString("Failed to remove %1, reloading list")
4291  .arg(recordingID));
4293  return;
4294  }
4295 
4297  QString groupname;
4298  if (sel_item)
4299  groupname = sel_item->GetData().toString();
4300 
4301  ProgramMap::iterator git = m_progLists.begin();
4302  while (git != m_progLists.end())
4303  {
4304  auto pit = (*git).begin();
4305  while (pit != (*git).end())
4306  {
4307  if ((*pit)->GetRecordingID() == recordingID)
4308  {
4309  if (!git.key().isEmpty() && git.key() == groupname)
4310  {
4311  MythUIButtonListItem *item_by_data =
4313  QVariant::fromValue(*pit));
4314  MythUIButtonListItem *item_cur =
4316 
4317  if (item_cur && (item_by_data == item_cur))
4318  {
4319  MythUIButtonListItem *item_next =
4320  m_recordingList->GetItemNext(item_cur);
4321  if (item_next)
4322  m_recordingList->SetItemCurrent(item_next);
4323  }
4324 
4325  m_recordingList->RemoveItem(item_by_data);
4326  }
4327  pit = (*git).erase(pit);
4328  }
4329  else
4330  {
4331  ++pit;
4332  }
4333  }
4334 
4335  if ((*git).empty())
4336  {
4337  if (!groupname.isEmpty() && (git.key() == groupname))
4338  {
4339  MythUIButtonListItem *next_item =
4340  m_groupList->GetItemNext(sel_item);
4341  if (next_item)
4342  m_groupList->SetItemCurrent(next_item);
4343 
4344  m_groupList->RemoveItem(sel_item);
4345 
4346  sel_item = next_item;
4347  groupname = "";
4348  if (sel_item)
4349  groupname = sel_item->GetData().toString();
4350  }
4351  git = m_progLists.erase(git);
4352  }
4353  else
4354  {
4355  ++git;
4356  }
4357  }
4358 
4360 }
4361 
4363 {
4364  m_programInfoCache.Add(evinfo);
4366 }
4367 
4369 {
4370  // Changing recording group full reload
4372  {
4374  }
4375  else
4376  {
4377  ProgramInfo *pginfo = FindProgramInUILists(recordingID);
4378  if (pginfo == nullptr)
4379  return;
4380  bool genPreview = (flags & ProgramInfoCache::PIC_MARK_CHANGED);
4381  UpdateUIListItem(pginfo, genPreview);
4382  }
4383 }
4384 
4386 {
4388  QCoreApplication::postEvent(this, new MythEvent("UPDATE_UI_LIST"));
4389 }
4390 
4392 {
4393  auto *helpPopup = new HelpPopup(m_popupStack);
4394 
4395  if (helpPopup->Create())
4396  m_popupStack->AddScreen(helpPopup);
4397  else
4398  delete helpPopup;
4399 }
4400 
4402 {
4403  auto *viewPopup = new ChangeView(m_popupStack, this, m_viewMask);
4404 
4405  if (viewPopup->Create())
4406  {
4407  connect(viewPopup, &ChangeView::save, this, &PlaybackBox::saveViewChanges);
4408  m_popupStack->AddScreen(viewPopup);
4409  }
4410  else
4411  {
4412  delete viewPopup;
4413  }
4414 }
4415 
4417 {
4418  if (m_viewMask == VIEW_NONE)
4420  gCoreContext->SaveSetting("DisplayGroupDefaultViewMask", (int)m_viewMask);
4421  gCoreContext->SaveBoolSetting("PlaybackWatchList",
4422  (m_viewMask & VIEW_WATCHLIST) != 0);
4423 }
4424 
4426 {
4427  QStringList groupNames;
4428  QStringList displayNames;
4429  QStringList groups;
4430  QStringList displayGroups;
4431 
4432  MSqlQuery query(MSqlQuery::InitCon());
4433 
4434  m_recGroupType.clear();
4435 
4436  uint totalItems = 0;
4437 
4438  // Add the group entries
4439  displayNames.append(QString("------- %1 -------").arg(tr("Groups")));
4440  groupNames.append("");
4441 
4442  // Find each recording group, and the number of recordings in each
4443  query.prepare("SELECT recgroup, COUNT(title) FROM recorded "
4444  "WHERE deletepending = 0 AND watched <= :WATCHED "
4445  "GROUP BY recgroup");
4446  query.bindValue(":WATCHED", (m_viewMask & VIEW_WATCHED));
4447  if (query.exec())
4448  {
4449  while (query.next())
4450  {
4451  QString dispGroup = query.value(0).toString();
4452  uint items = query.value(1).toInt();
4453 
4454  if ((dispGroup != "LiveTV" || (m_viewMask & VIEW_LIVETVGRP)) &&
4455  (dispGroup != "Deleted"))
4456  totalItems += items;
4457 
4458  groupNames.append(dispGroup);
4459 
4460  dispGroup = (dispGroup == "Default") ? tr("Default") : dispGroup;
4461  dispGroup = (dispGroup == "Deleted") ? tr("Deleted") : dispGroup;
4462  dispGroup = (dispGroup == "LiveTV") ? tr("Live TV") : dispGroup;
4463 
4464  displayNames.append(tr("%1 [%n item(s)]", nullptr, items).arg(dispGroup));
4465 
4466  m_recGroupType[query.value(0).toString()] = "recgroup";
4467  }
4468  }
4469 
4470  // Create and add the "All Programs" entry
4471  displayNames.push_front(tr("%1 [%n item(s)]", nullptr, totalItems)
4472  .arg(ProgramInfo::i18n("All Programs")));
4473  groupNames.push_front("All Programs");
4474  m_recGroupType["All Programs"] = "recgroup";
4475 
4476  // Find each category, and the number of recordings in each
4477  query.prepare("SELECT DISTINCT category, COUNT(title) FROM recorded "
4478  "WHERE deletepending = 0 AND watched <= :WATCHED "
4479  "GROUP BY category");
4480  query.bindValue(":WATCHED", (m_viewMask & VIEW_WATCHED));
4481  if (query.exec())
4482  {
4483  int unknownCount = 0;
4484  while (query.next())
4485  {
4486  uint items = query.value(1).toInt();
4487  QString dispGroup = query.value(0).toString();
4488  if (dispGroup.isEmpty())
4489  {
4490  unknownCount += items;
4491  dispGroup = tr("Unknown");
4492  }
4493  else if (dispGroup == tr("Unknown"))
4494  {
4495  unknownCount += items;
4496  }
4497 
4498  if ((!m_recGroupType.contains(dispGroup)) &&
4499  (dispGroup != tr("Unknown")))
4500  {
4501  displayGroups += tr("%1 [%n item(s)]", nullptr, items).arg(dispGroup);
4502  groups += dispGroup;
4503 
4504  m_recGroupType[dispGroup] = "category";
4505  }
4506  }
4507 
4508  if (unknownCount > 0)
4509  {
4510  QString dispGroup = tr("Unknown");
4511  uint items = unknownCount;
4512  displayGroups += tr("%1 [%n item(s)]", nullptr, items).arg(dispGroup);
4513  groups += dispGroup;
4514 
4515  m_recGroupType[dispGroup] = "category";
4516  }
4517  }
4518 
4519  // Add the category entries
4520  displayNames.append(QString("------- %1 -------").arg(tr("Categories")));
4521  groupNames.append("");
4522  groups.sort();
4523  displayGroups.sort();
4524  QStringList::iterator it;
4525  for (it = displayGroups.begin(); it != displayGroups.end(); ++it)
4526  displayNames.append(*it);
4527  for (it = groups.begin(); it != groups.end(); ++it)
4528  groupNames.append(*it);
4529 
4530  QString label = tr("Change Filter");
4531 
4532  auto *recGroupPopup = new GroupSelector(m_popupStack, label, displayNames,
4533  groupNames, m_recGroup);
4534 
4535  if (recGroupPopup->Create())
4536  {
4537  m_usingGroupSelector = true;
4538  m_groupSelected = false;
4539  connect(recGroupPopup, &GroupSelector::result,
4541  connect(recGroupPopup, &MythScreenType::Exiting,
4543  m_popupStack->AddScreen(recGroupPopup);
4544  }
4545  else
4546  {
4547  delete recGroupPopup;
4548  }
4549 }
4550 
4552 {
4553  if (m_groupSelected)
4554  return;
4555 
4556  if (m_firstGroup)
4557  Close();
4558 
4559  m_usingGroupSelector = false;
4560 }
4561 
4562 void PlaybackBox::setGroupFilter(const QString &recGroup)
4563 {
4564  QString newRecGroup = recGroup;
4565 
4566  if (newRecGroup.isEmpty())
4567  return;
4568 
4569  m_firstGroup = false;
4570  m_usingGroupSelector = false;
4571 
4572  if (newRecGroup == ProgramInfo::i18n("Default"))
4573  newRecGroup = "Default";
4574  else if (newRecGroup == ProgramInfo::i18n("All Programs"))
4575  newRecGroup = "All Programs";
4576  else if (newRecGroup == ProgramInfo::i18n("LiveTV"))
4577  newRecGroup = "LiveTV";
4578  else if (newRecGroup == ProgramInfo::i18n("Deleted"))
4579  newRecGroup = "Deleted";
4580 
4581  m_recGroup = newRecGroup;
4582 
4584 
4585  // Since the group filter is changing, the current position in the lists
4586  // is meaningless -- so reset the lists so the position won't be saved.
4588  m_groupList->Reset();
4589 
4590  UpdateUILists();
4591 
4592  if (gCoreContext->GetBoolSetting("RememberRecGroup",true))
4593  gCoreContext->SaveSetting("DisplayRecGroup", m_recGroup);
4594 
4595  if (m_recGroupType[m_recGroup] == "recgroup")
4596  gCoreContext->SaveSetting("DisplayRecGroupIsCategory", 0);
4597  else
4598  gCoreContext->SaveSetting("DisplayRecGroupIsCategory", 1);
4599 }
4600 
4601 QString PlaybackBox::getRecGroupPassword(const QString &group)
4602 {
4603  return m_recGroupPwCache.value(group);
4604 }
4605 
4607 {
4608  m_recGroupPwCache.clear();
4609 
4610  MSqlQuery query(MSqlQuery::InitCon());
4611  query.prepare("SELECT recgroup, password FROM recgroups "
4612  "WHERE password IS NOT NULL AND password <> '';");
4613 
4614  if (query.exec())
4615  {
4616  while (query.next())
4617  {
4618  QString recgroup = query.value(0).toString();
4619 
4620  if (recgroup == ProgramInfo::i18n("Default"))
4621  recgroup = "Default";
4622  else if (recgroup == ProgramInfo::i18n("All Programs"))
4623  recgroup = "All Programs";
4624  else if (recgroup == ProgramInfo::i18n("LiveTV"))
4625  recgroup = "LiveTV";
4626  else if (recgroup == ProgramInfo::i18n("Deleted"))
4627  recgroup = "Deleted";
4628 
4629  m_recGroupPwCache.insert(recgroup, query.value(1).toString());
4630  }
4631  }
4632 }
4633 
4635 void PlaybackBox::ShowRecGroupChanger(bool use_playlist)
4636 {
4637  m_opOnPlaylist = use_playlist;
4638 
4639  ProgramInfo *pginfo = nullptr;
4640  if (use_playlist)
4641  {
4642  if (!m_playList.empty())
4643  pginfo = FindProgramInUILists(m_playList[0]);
4644  }
4645  else
4646  {
4647  pginfo = GetCurrentProgram();
4648  }
4649 
4650  if (!pginfo)
4651  return;
4652 
4653  MSqlQuery query(MSqlQuery::InitCon());
4654  query.prepare(
4655  "SELECT g.recgroup, COUNT(r.title) FROM recgroups g "
4656  "LEFT JOIN recorded r ON g.recgroupid=r.recgroupid AND r.deletepending = 0 "
4657  "WHERE g.recgroupid != 2 AND g.recgroupid != 3 "
4658  "GROUP BY g.recgroupid ORDER BY g.recgroup");
4659 
4660  QStringList displayNames(tr("Add New"));
4661  QStringList groupNames("addnewgroup");
4662 
4663  if (!query.exec())
4664  return;
4665 
4666  while (query.next())
4667  {
4668  QString dispGroup = query.value(0).toString();
4669  groupNames.push_back(dispGroup);
4670 
4671  if (dispGroup == "Default")
4672  dispGroup = tr("Default");
4673  else if (dispGroup == "LiveTV")
4674  dispGroup = tr("Live TV");
4675  else if (dispGroup == "Deleted")
4676  dispGroup = tr("Deleted");
4677 
4678  displayNames.push_back(tr("%1 [%n item(s)]", "", query.value(1).toInt())
4679  .arg(dispGroup));
4680  }
4681 
4682  QString label = tr("Select Recording Group") +
4683  CreateProgramInfoString(*pginfo);
4684 
4685  auto *rgChanger = new GroupSelector(m_popupStack, label, displayNames,
4686  groupNames, pginfo->GetRecordingGroup());
4687 
4688  if (rgChanger->Create())
4689  {
4690  connect(rgChanger, &GroupSelector::result, this, &PlaybackBox::setRecGroup);
4691  m_popupStack->AddScreen(rgChanger);
4692  }
4693  else
4694  {
4695  delete rgChanger;
4696  }
4697 }
4698 
4700 void PlaybackBox::ShowPlayGroupChanger(bool use_playlist)
4701 {
4702  m_opOnPlaylist = use_playlist;
4703 
4704  ProgramInfo *pginfo = nullptr;
4705  if (use_playlist)
4706  {
4707  if (!m_playList.empty())
4708  pginfo = FindProgramInUILists(m_playList[0]);
4709  }
4710  else
4711  {
4712  pginfo = GetCurrentProgram();
4713  }
4714 
4715  if (!pginfo)
4716  return;
4717 
4718  QStringList groupNames(tr("Default"));
4719  QStringList displayNames("Default");
4720 
4721  QStringList list = PlayGroup::GetNames();
4722  for (const auto& name : std::as_const(list))
4723  {
4724  displayNames.push_back(name);
4725  groupNames.push_back(name);
4726  }
4727 
4728  QString label = tr("Select Playback Group") +
4729  CreateProgramInfoString(*pginfo);
4730 
4731  auto *pgChanger = new GroupSelector(m_popupStack, label,displayNames,
4732  groupNames, pginfo->GetPlaybackGroup());
4733 
4734  if (pgChanger->Create())
4735  {
4736  connect(pgChanger, &GroupSelector::result,
4737  this, &PlaybackBox::setPlayGroup);
4738  m_popupStack->AddScreen(pgChanger);
4739  }
4740  else
4741  {
4742  delete pgChanger;
4743  }
4744 }
4745 
4747 {
4748  QList<uint>::Iterator it;
4749 
4750  for (it = m_playList.begin(); it != m_playList.end(); ++it)
4751  {
4752  ProgramInfo *tmpItem = FindProgramInUILists(*it);
4753  if (tmpItem != nullptr)
4754  {
4755  if (!tmpItem->IsAutoExpirable() && turnOn)
4756  tmpItem->SaveAutoExpire(kNormalAutoExpire, true);
4757  else if (tmpItem->IsAutoExpirable() && !turnOn)
4758  tmpItem->SaveAutoExpire(kDisableAutoExpire, true);
4759  }
4760  }
4761 }
4762 
4764 {
4765  QList<uint>::Iterator it;
4766 
4767  for (it = m_playList.begin(); it != m_playList.end(); ++it)
4768  {
4769  ProgramInfo *tmpItem = FindProgramInUILists(*it);
4770  if (tmpItem != nullptr)
4771  {
4772  tmpItem->SaveWatched(turnOn);
4773  }
4774  }
4775 
4776  doClearPlaylist();
4777  UpdateUILists();
4778 }
4779 
4781 {
4782  ProgramInfo *pgInfo = GetCurrentProgram();
4783 
4785 
4786  auto *editMetadata = new RecMetadataEdit(mainStack, pgInfo);
4787 
4788  if (editMetadata->Create())
4789  {
4790  connect(editMetadata, &RecMetadataEdit::result,
4792  mainStack->AddScreen(editMetadata);
4793  }
4794  else
4795  {
4796  delete editMetadata;
4797  }
4798 }
4799 
4800 void PlaybackBox::saveRecMetadata(const QString &newTitle,
4801  const QString &newSubtitle,
4802  const QString &newDescription,
4803  const QString &newInetref,
4804  uint newSeason,
4805  uint newEpisode)
4806 {
4808 
4809  if (!item)
4810  return;
4811 
4812  auto *pginfo = item->GetData().value<ProgramInfo *>();
4813 
4814  if (!pginfo)
4815  return;
4816 
4817  QString groupname = m_groupList->GetItemCurrent()->GetData().toString();
4818 
4819  if (groupname == pginfo->GetTitle().toLower() &&
4820  newTitle != pginfo->GetTitle())
4821  {
4822  m_recordingList->RemoveItem(item);
4823  }
4824  else
4825  {
4826  QString tempSubTitle = newTitle;
4827  if (!newSubtitle.trimmed().isEmpty())
4828  tempSubTitle = QString("%1 - \"%2\"")
4829  .arg(tempSubTitle, newSubtitle);
4830 
4831  QString seasone;
4832  QString seasonx;
4833  QString season;
4834  QString episode;
4835  if (newSeason > 0 || newEpisode > 0)
4836  {
4837  season = StringUtil::intToPaddedString(newSeason, 1);
4838  episode = StringUtil::intToPaddedString(newEpisode, 1);
4839  seasone = QString("s%1e%2")
4840  .arg(StringUtil::intToPaddedString(newSeason, 2),
4841  StringUtil::intToPaddedString(newEpisode, 2));
4842  seasonx = QString("%1x%2")
4843  .arg(StringUtil::intToPaddedString(newSeason, 1),
4844  StringUtil::intToPaddedString(newEpisode, 2));
4845  }
4846 
4847  item->SetText(tempSubTitle, "titlesubtitle");
4848  item->SetText(newTitle, "title");
4849  item->SetText(newSubtitle, "subtitle");
4850  item->SetText(newInetref, "inetref");
4851  item->SetText(seasonx, "00x00");
4852  item->SetText(seasone, "s00e00");
4853  item->SetText(season, "season");
4854  item->SetText(episode, "episode");
4855  if (newDescription != nullptr)
4856  item->SetText(newDescription, "description");
4857  }
4858 
4859  pginfo->SaveInetRef(newInetref);
4860  pginfo->SaveSeasonEpisode(newSeason, newEpisode);
4861 
4862  RecordingInfo ri(*pginfo);
4863  ri.ApplyRecordRecTitleChange(newTitle, newSubtitle, newDescription);
4864  *pginfo = ri;
4865 }
4866 
4867 void PlaybackBox::setRecGroup(QString newRecGroup)
4868 {
4869  newRecGroup = newRecGroup.simplified();
4870 
4871  if (newRecGroup.isEmpty())
4872  return;
4873 
4874  if (newRecGroup == "addnewgroup")
4875  {
4876  MythScreenStack *popupStack =
4877  GetMythMainWindow()->GetStack("popup stack");
4878 
4879  auto *newgroup = new MythTextInputDialog(popupStack,
4880  tr("New Recording Group"));
4881 
4882  connect(newgroup, &MythTextInputDialog::haveResult,
4883  this, &PlaybackBox::setRecGroup);
4884 
4885  if (newgroup->Create())
4886  popupStack->AddScreen(newgroup, false);
4887  else
4888  delete newgroup;
4889  return;
4890  }
4891 
4892  RecordingRule record;
4893  record.LoadTemplate("Default");
4894  AutoExpireType defaultAutoExpire =
4896 
4897  if (m_opOnPlaylist)
4898  {
4899  for (int id : std::as_const(m_playList))
4900  {
4902  if (!p)
4903  continue;
4904 
4905  if ((p->GetRecordingGroup() == "LiveTV") &&
4906  (newRecGroup != "LiveTV"))
4907  {
4908  p->SaveAutoExpire(defaultAutoExpire);
4909  }
4910  else if ((p->GetRecordingGroup() != "LiveTV") &&
4911  (newRecGroup == "LiveTV"))
4912  {
4913  p->SaveAutoExpire(kLiveTVAutoExpire);
4914  }
4915 
4916  RecordingInfo ri(*p);
4917  ri.ApplyRecordRecGroupChange(newRecGroup);
4918  *p = ri;
4919  }
4920  doClearPlaylist();
4921  UpdateUILists();
4922  return;
4923  }
4924 
4926  if (!p)
4927  return;
4928 
4929  if ((p->GetRecordingGroup() == "LiveTV") && (newRecGroup != "LiveTV"))
4930  p->SaveAutoExpire(defaultAutoExpire);
4931  else if ((p->GetRecordingGroup() != "LiveTV") && (newRecGroup == "LiveTV"))
4932  p->SaveAutoExpire(kLiveTVAutoExpire);
4933 
4934  RecordingInfo ri(*p);
4935  ri.ApplyRecordRecGroupChange(newRecGroup);
4936  *p = ri;
4937  UpdateUILists();
4938 }
4939 
4940 void PlaybackBox::setPlayGroup(QString newPlayGroup)
4941 {
4942  ProgramInfo *tmpItem = GetCurrentProgram();
4943 
4944  if (newPlayGroup.isEmpty() || !tmpItem)
4945  return;
4946 
4947  if (newPlayGroup == tr("Default"))
4948  newPlayGroup = "Default";
4949 
4950  if (m_opOnPlaylist)
4951  {
4952  QList<uint>::Iterator it;
4953 
4954  for (it = m_playList.begin(); it != m_playList.end(); ++it )
4955  {
4956  tmpItem = FindProgramInUILists(*it);
4957  if (tmpItem)
4958  {
4959  RecordingInfo ri(*tmpItem);
4960  ri.ApplyRecordPlayGroupChange(newPlayGroup);
4961  *tmpItem = ri;
4962  }
4963  }
4964  doClearPlaylist();
4965  }
4966  else
4967  {
4968  RecordingInfo ri(*tmpItem);
4969  ri.ApplyRecordPlayGroupChange(newPlayGroup);
4970  *tmpItem = ri;
4971  }
4972 }
4973 
4975 {
4977 
4978  if (!item)
4979  return;
4980 
4981  QString currentPassword = getRecGroupPassword(m_recGroup);
4982 
4983  auto *pwChanger = new PasswordChange(m_popupStack, currentPassword);
4984 
4985  if (pwChanger->Create())
4986  {
4987  connect(pwChanger, &PasswordChange::result,
4989  m_popupStack->AddScreen(pwChanger);
4990  }
4991  else
4992  {
4993  delete pwChanger;
4994  }
4995 }
4996 
4997 void PlaybackBox::SetRecGroupPassword(const QString &newPassword)
4998 {
4999  MSqlQuery query(MSqlQuery::InitCon());
5000 
5001  query.prepare("UPDATE recgroups SET password = :PASSWD WHERE "
5002  "recgroup = :RECGROUP");
5003  query.bindValue(":RECGROUP", m_recGroup);
5004  query.bindValue(":PASSWD", newPassword);
5005 
5006  if (!query.exec())
5007  MythDB::DBError("PlaybackBox::SetRecGroupPassword",
5008  query);
5009 
5010  if (newPassword.isEmpty())
5011  m_recGroupPwCache.remove(m_recGroup);
5012  else
5013  m_recGroupPwCache.insert(m_recGroup, newPassword);
5014 }
5015 
5017 
5019 {
5020  if (!LoadWindowFromXML("recordings-ui.xml", "groupselector", this))
5021  return false;
5022 
5023  MythUIText *labelText = dynamic_cast<MythUIText*> (GetChild("label"));
5024  MythUIButtonList *groupList = dynamic_cast<MythUIButtonList*>
5025  (GetChild("groups"));
5026 
5027  if (!groupList)
5028  {
5029  LOG(VB_GENERAL, LOG_ERR, LOC +
5030  "Theme is missing 'groups' button list.");
5031  return false;
5032  }
5033 
5034  if (labelText)
5035  labelText->SetText(m_label);
5036 
5037  for (int i = 0; i < m_list.size(); ++i)
5038  {
5039  new MythUIButtonListItem(groupList, m_list.at(i),
5040  QVariant::fromValue(m_data.at(i)));
5041  }
5042 
5043  // Set the current position in the list
5044  groupList->SetValueByData(QVariant::fromValue(m_selected));
5045 
5046  BuildFocusList();
5047 
5048  connect(groupList, &MythUIButtonList::itemClicked,
5049  this, &GroupSelector::AcceptItem);
5050 
5051  return true;
5052 }
5053 
5055 {
5056  if (!item)
5057  return;
5058 
5059  // ignore the dividers
5060  if (item->GetData().toString().isEmpty())
5061  return;
5062 
5063  QString group = item->GetData().toString();
5064  emit result(group);
5065  Close();
5066 }
5067 
5069 
5071 {
5072  if (!LoadWindowFromXML("recordings-ui.xml", "changeview", this))
5073  return false;
5074 
5075  MythUICheckBox *checkBox = dynamic_cast<MythUICheckBox*>(GetChild("titles"));
5076  if (checkBox)
5077  {
5080  connect(checkBox, &MythUICheckBox::toggled,
5082  }
5083 
5084  checkBox = dynamic_cast<MythUICheckBox*>(GetChild("categories"));
5085  if (checkBox)
5086  {
5089  connect(checkBox, &MythUICheckBox::toggled,
5091  }
5092 
5093  checkBox = dynamic_cast<MythUICheckBox*>(GetChild("recgroups"));
5094  if (checkBox)
5095  {
5098  connect(checkBox, &MythUICheckBox::toggled,
5100  }
5101 
5102  // TODO Do we need two separate settings to determine whether the watchlist
5103  // is shown? The filter setting be enough?
5104  checkBox = dynamic_cast<MythUICheckBox*>(GetChild("watchlist"));
5105  if (checkBox)
5106  {
5109  connect(checkBox, &MythUICheckBox::toggled,
5111  }
5112  //
5113 
5114  checkBox = dynamic_cast<MythUICheckBox*>(GetChild("searches"));
5115  if (checkBox)
5116  {
5119  connect(checkBox, &MythUICheckBox::toggled,
5121  }
5122 
5123  // TODO Do we need two separate settings to determine whether livetv
5124  // recordings are shown? Same issue as the watchlist above
5125  checkBox = dynamic_cast<MythUICheckBox*>(GetChild("livetv"));
5126  if (checkBox)
5127  {
5130  connect(checkBox, &MythUICheckBox::toggled,
5132  }
5133  //
5134 
5135  checkBox = dynamic_cast<MythUICheckBox*>(GetChild("watched"));
5136  if (checkBox)
5137  {
5140  connect(checkBox, &MythUICheckBox::toggled,
5142  }
5143 
5144  MythUIButton *savebutton = dynamic_cast<MythUIButton*>(GetChild("save"));
5145  connect(savebutton, &MythUIButton::Clicked, this, &ChangeView::SaveChanges);
5146 
5147  BuildFocusList();
5148 
5149  return true;
5150 }
5151 
5153 {
5154  emit save();
5155  Close();
5156 }
5157 
5159 
5161 {
5162  if (!LoadWindowFromXML("recordings-ui.xml", "passwordchanger", this))
5163  return false;
5164 
5165  m_oldPasswordEdit = dynamic_cast<MythUITextEdit *>(GetChild("oldpassword"));
5166  m_newPasswordEdit = dynamic_cast<MythUITextEdit *>(GetChild("newpassword"));
5167  m_okButton = dynamic_cast<MythUIButton *>(GetChild("ok"));
5168 
5170  {
5171  LOG(VB_GENERAL, LOG_ERR, LOC +
5172  "Window 'passwordchanger' is missing required elements.");
5173  return false;
5174  }
5175 
5178 // if (m_oldPassword.isEmpty())
5179 // m_oldPasswordEdit->SetDisabled(true);
5182 
5183  BuildFocusList();
5184 
5188 
5189  return true;
5190 }
5191 
5193 {
5194  QString newText = m_oldPasswordEdit->GetText();
5195  bool ok = (newText == m_oldPassword);
5196  m_okButton->SetEnabled(ok);
5197 }
5198 
5199 
5201 {
5202  emit result(m_newPasswordEdit->GetText());
5203  Close();
5204 }
5205 
5207 
5209  : MythScreenType(lparent, "recmetadataedit"),
5210  m_progInfo(pginfo),
5211  m_metadataFactory(new MetadataFactory(this))
5212 {
5213  m_popupStack = GetMythMainWindow()->GetStack("popup stack");
5214 }
5215 
5217 {
5218  if (!LoadWindowFromXML("recordings-ui.xml", "editmetadata", this))
5219  return false;
5220 
5221  m_titleEdit = dynamic_cast<MythUITextEdit*>(GetChild("title"));
5222  m_subtitleEdit = dynamic_cast<MythUITextEdit*>(GetChild("subtitle"));
5223  m_descriptionEdit = dynamic_cast<MythUITextEdit*>(GetChild("description"));
5224  m_inetrefEdit = dynamic_cast<MythUITextEdit*>(GetChild("inetref"));
5225  MythUIButton *inetrefClear = dynamic_cast<MythUIButton*>
5226  (GetChild("inetref_clear"));
5227  m_seasonSpin = dynamic_cast<MythUISpinBox*>(GetChild("season"));
5228  m_episodeSpin = dynamic_cast<MythUISpinBox*>(GetChild("episode"));
5229  MythUIButton *okButton = dynamic_cast<MythUIButton*>(GetChild("ok"));
5230  m_queryButton = dynamic_cast<MythUIButton*>(GetChild("query_button"));
5231 
5233  !m_episodeSpin || !okButton)
5234  {
5235  LOG(VB_GENERAL, LOG_ERR, LOC +
5236  "Window 'editmetadata' is missing required elements.");
5237  return false;
5238  }
5239 
5241  m_titleEdit->SetMaxLength(128);
5244  if (m_descriptionEdit)
5245  {
5248  }
5251  m_seasonSpin->SetRange(0,9999,1,5);
5253  m_episodeSpin->SetRange(0,9999,1,10);
5255 
5256  connect(inetrefClear, &MythUIButton::Clicked, this, &RecMetadataEdit::ClearInetref);
5257  connect(okButton, &MythUIButton::Clicked, this, &RecMetadataEdit::SaveChanges);
5258  if (m_queryButton)
5259  {
5261  }
5262 
5263  BuildFocusList();
5264 
5265  return true;
5266 }
5267 
5269 {
5270  m_inetrefEdit->SetText("");
5271 }
5272 
5274 {
5275  QString newRecTitle = m_titleEdit->GetText();
5276  QString newRecSubtitle = m_subtitleEdit->GetText();
5277  QString newRecDescription = nullptr;
5278  QString newRecInetref = nullptr;
5279  uint newRecSeason = 0;
5280  uint newRecEpisode = 0;
5281  if (m_descriptionEdit)
5282  newRecDescription = m_descriptionEdit->GetText();
5283  newRecInetref = m_inetrefEdit->GetText();
5284  newRecSeason = m_seasonSpin->GetIntValue();
5285  newRecEpisode = m_episodeSpin->GetIntValue();
5286 
5287  if (newRecTitle.isEmpty())
5288  return;
5289 
5290  emit result(newRecTitle, newRecSubtitle, newRecDescription,
5291  newRecInetref, newRecSeason, newRecEpisode);
5292  Close();
5293 }
5294 
5296 {
5297  if (m_busyPopup)
5298  return;
5299 
5300  m_busyPopup = new MythUIBusyDialog(tr("Trying to manually find this "
5301  "recording online..."),
5302  m_popupStack,
5303  "metaoptsdialog");
5304 
5305  if (m_busyPopup->Create())
5307 
5308  auto *lookup = new MetadataLookup();
5309  lookup->SetStep(kLookupSearch);
5310  lookup->SetType(kMetadataRecording);
5312 
5313  if (type == kUnknownVideo)
5314  {
5315  if (m_seasonSpin->GetIntValue() == 0 &&
5316  m_episodeSpin->GetIntValue() == 0 &&
5317  m_subtitleEdit->GetText().isEmpty())
5318  {
5319  lookup->SetSubtype(kProbableMovie);
5320  }
5321  else
5322  {
5323  lookup->SetSubtype(kProbableTelevision);
5324  }
5325  }
5326  else
5327  {
5328  // we could determine the type from the inetref
5329  lookup->SetSubtype(type);
5330  }
5331  lookup->SetAllowGeneric(true);
5332  lookup->SetHandleImages(false);
5333  lookup->SetHost(gCoreContext->GetMasterHostName());
5334  lookup->SetTitle(m_titleEdit->GetText());
5335  lookup->SetSubtitle(m_subtitleEdit->GetText());
5336  lookup->SetInetref(m_inetrefEdit->GetText());
5337  lookup->SetCollectionref(m_inetrefEdit->GetText());
5338  lookup->SetSeason(m_seasonSpin->GetIntValue());
5339  lookup->SetEpisode(m_episodeSpin->GetIntValue());
5340  lookup->SetAutomatic(false);
5341 
5342  m_metadataFactory->Lookup(lookup);
5343 }
5344 
5346 {
5347  if (!lookup)
5348  return;
5349 
5350  m_inetrefEdit->SetText(lookup->GetInetref());
5351  m_seasonSpin->SetValue(lookup->GetSeason());
5352  m_episodeSpin->SetValue(lookup->GetEpisode());
5353  if (!lookup->GetSubtitle().isEmpty())
5354  {
5355  m_subtitleEdit->SetText(lookup->GetSubtitle());
5356  }
5357  if (!lookup->GetDescription().isEmpty())
5358  {
5360  }
5361 }
5362 
5364 {
5365  QueryComplete(lookup);
5366 }
5367 
5368 void RecMetadataEdit::customEvent(QEvent *levent)
5369 {
5370  if (levent->type() == MetadataFactoryMultiResult::kEventType)
5371  {
5372  if (m_busyPopup)
5373  {
5374  m_busyPopup->Close();
5375  m_busyPopup = nullptr;
5376  }
5377 
5378  auto *mfmr = dynamic_cast<MetadataFactoryMultiResult*>(levent);
5379 
5380  if (!mfmr)
5381  return;
5382 
5383  MetadataLookupList list = mfmr->m_results;
5384 
5385  auto *resultsdialog = new MetadataResultsDialog(m_popupStack, list);
5386 
5387  connect(resultsdialog, &MetadataResultsDialog::haveResult,
5389  Qt::QueuedConnection);
5390 
5391  if (resultsdialog->Create())
5392  m_popupStack->AddScreen(resultsdialog);
5393  }
5394  else if (levent->type() == MetadataFactorySingleResult::kEventType)
5395  {
5396  if (m_busyPopup)
5397  {
5398  m_busyPopup->Close();
5399  m_busyPopup = nullptr;
5400  }
5401 
5402  auto *mfsr = dynamic_cast<MetadataFactorySingleResult*>(levent);
5403 
5404  if (!mfsr || !mfsr->m_result)
5405  return;
5406 
5407  QueryComplete(mfsr->m_result);
5408  }
5409  else if (levent->type() == MetadataFactoryNoResult::kEventType)
5410  {
5411  if (m_busyPopup)
5412  {
5413  m_busyPopup->Close();
5414  m_busyPopup = nullptr;
5415  }
5416 
5417  auto *mfnr = dynamic_cast<MetadataFactoryNoResult*>(levent);
5418 
5419  if (!mfnr)
5420  return;
5421 
5422  QString title = tr("No match found for this recording. You can "
5423  "try entering a TVDB/TMDB number, season, and "
5424  "episode manually.");
5425 
5426  auto *okPopup = new MythConfirmationDialog(m_popupStack, title, false);
5427 
5428  if (okPopup->Create())
5429  m_popupStack->AddScreen(okPopup);
5430  }
5431 }
5432 
5434 
5436 {
5437  if (!LoadWindowFromXML("recordings-ui.xml", "iconhelp", this))
5438  return false;
5439 
5440  m_iconList = dynamic_cast<MythUIButtonList*>(GetChild("iconlist"));
5441 
5442  if (!m_iconList)
5443  {
5444  LOG(VB_GENERAL, LOG_ERR, LOC +
5445  "Window 'iconhelp' is missing required elements.");
5446  return false;
5447  }
5448 
5449  BuildFocusList();
5450 
5451  addItem("watched", tr("Recording has been watched"));
5452  addItem("commflagged", tr("Commercials are flagged"));
5453  addItem("cutlist", tr("An editing cutlist is present"));
5454  addItem("autoexpire", tr("The program is able to auto-expire"));
5455  addItem("processing", tr("Commercials are being flagged"));
5456  addItem("bookmark", tr("A bookmark is set"));
5457 #if 0
5458  addItem("inuse", tr("Recording is in use"));
5459  addItem("transcoded", tr("Recording has been transcoded"));
5460 #endif
5461 
5462  addItem("mono", tr("Recording is in Mono"));
5463  addItem("stereo", tr("Recording is in Stereo"));
5464  addItem("surround", tr("Recording is in Surround Sound"));
5465  addItem("dolby", tr("Recording is in Dolby Surround Sound"));
5466 
5467  addItem("cc", tr("Recording is Closed Captioned"));
5468  addItem("subtitles", tr("Recording has Subtitles Available"));
5469  addItem("onscreensub", tr("Recording is Subtitled"));
5470 
5471  addItem("SD", tr("Recording is in Standard Definition"));
5472  addItem("widescreen", tr("Recording is Widescreen"));
5473  addItem("hdtv", tr("Recording is in High Definition"));
5474  addItem("hd720", tr("Recording is in 720p High Definition"));
5475  addItem("hd1080i", tr("Recording is in 1080i High Definition"));
5476  addItem("hd1080p", tr("Recording is in 1080p High Definition"));
5477  addItem("uhd4Ki", tr("Recording is in 4k(interlaced) UHD resolution"));
5478  addItem("uhd4Kp", tr("Recording is in 4k UHD resolution"));
5479  addItem("mpeg2", tr("Recording is using MPEG-2 codec"));
5480  addItem("avchd", tr("Recording is using AVC/H.264 codec"));
5481  addItem("hevc", tr("Recording is using HEVC/H.265 codec"));
5482 // addItem("preserved", tr("Recording is preserved"));
5483 
5484  return true;
5485 }
5486 
5487 void HelpPopup::addItem(const QString &state, const QString &text)
5488 {
5489  auto *item = new MythUIButtonListItem(m_iconList, text);
5490  item->DisplayState(state, "icons");
5491 }
5492 
5494 {
5495  QDateTime now = QDateTime::currentDateTime();
5496  if (!m_lastUpdated.isValid() ||
5497  m_lastUpdated.msecsTo(now) >= kInvalidateTimeMs.count())
5498  {
5499  QMap<int, JobQueueEntry> jobs;
5501  m_jobs.clear();
5502  for (const auto& job : std::as_const(jobs))
5503  {
5504  m_jobs.insert(qMakePair(job.chanid, job.recstartts), job);
5505  }
5506  m_lastUpdated = now;
5507  }
5508 }
5509 
5511  const QDateTime &recstartts)
5512 {
5513  Update();
5514  QList<JobQueueEntry> values = m_jobs.values(qMakePair(chanid, recstartts));
5515  auto end = values.cend();
5516  for (auto iter = values.cbegin(); iter != end; ++iter)
5517  {
5518  if (iter->type == jobType)
5519  return JobQueue::IsJobStatusQueued(iter->status);
5520  }
5521  return false;
5522 }
5523 
5525  const QDateTime &recstartts)
5526 {
5527  Update();
5528  QList<JobQueueEntry> values = m_jobs.values(qMakePair(chanid, recstartts));
5529  auto end = values.cend();
5530  for (auto iter = values.cbegin(); iter != end; ++iter)
5531  {
5532  if (iter->type == jobType)
5533  return JobQueue::IsJobStatusRunning(iter->status);
5534  }
5535  return false;
5536 }
5537 
5539  const QDateTime &recstartts)
5540 {
5541  return IsJobQueued(jobType, chanid, recstartts) ||
5542  IsJobRunning(jobType, chanid, recstartts);
5543 }
5544 
5545 /* vim: set expandtab tabstop=4 shiftwidth=4: */
MetadataFactory::Lookup
void Lookup(ProgramInfo *pginfo, bool automatic=true, bool getimages=true, bool allowgeneric=false)
Definition: metadatafactory.cpp:138
ProgramInfoCache::Add
void Add(const ProgramInfo &pginfo)
Adds a ProgramInfo to the cache.
Definition: programinfocache.cpp:274
PlaybackBoxHelper::DeleteRecording
void DeleteRecording(uint recordingID, bool forceDelete, bool forgetHistory)
Definition: playbackboxhelper.cpp:377
RecordingInfo::ApplyRecordPlayGroupChange
void ApplyRecordPlayGroupChange(const QString &newplaygroup)
Sets the recording group, both in this RecordingInfo and in the database.
Definition: recordinginfo.cpp:744
PlaybackBox::toggleRecGroupView
void toggleRecGroupView(bool setOn)
Definition: playbackbox.h:216
PlaybackBox::updateIcons
void updateIcons(const ProgramInfo *pginfo=nullptr)
Definition: playbackbox.cpp:1151
MythUIButton::Clicked
void Clicked()
MythUIButtonList::GetItemAt
MythUIButtonListItem * GetItemAt(int pos) const
Definition: mythuibuttonlist.cpp:1700
ProgramInfo::QueryIsDeleteCandidate
bool QueryIsDeleteCandidate(bool one_playback_allowed=false) const
Returns true iff this is a recording, it is not in use (except by the recorder), and at most one play...
Definition: programinfo.cpp:3273
MythUIButtonList::StopLoad
int StopLoad(void)
Definition: mythuibuttonlist.cpp:2812
MythScreenType::LoadInBackground
void LoadInBackground(const QString &message="")
Definition: mythscreentype.cpp:283
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
ProgramInfo::SetAvailableStatus
void SetAvailableStatus(AvailableStatusType status, const QString &where)
Definition: programinfo.cpp:2462
mythuimetadataresults.h
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
PlaybackBox::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: playbackbox.cpp:3791
PlaybackBox::VIEW_NONE
@ VIEW_NONE
Definition: playbackbox.h:88
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:317
TVPlaybackState::RequestEmbedding
void RequestEmbedding(bool Embed, const QRect &Rect={}, const QStringList &Data={})
MythUIButtonList::GetTopItemPos
int GetTopItemPos(void) const
Definition: mythuibuttonlist.h:242
PlaybackBox::VIEW_WATCHLIST
@ VIEW_WATCHLIST
Definition: playbackbox.h:92
PlaybackBox::doCreateTranscodingProfilesMenu
void doCreateTranscodingProfilesMenu()
Definition: playbackbox.h:171
mythevent.h
MythUITextEdit::SetMaxLength
void SetMaxLength(int length)
Definition: mythuitextedit.cpp:193
bool
bool
Definition: pxsup2dast.c:30
PlaybackBox::DeleteForceAllRemaining
void DeleteForceAllRemaining(void)
Definition: playbackbox.h:201
PlaybackBox::RunPlaybackBox
static void * RunPlaybackBox(void *player, bool showTV)
Definition: playbackbox.cpp:372
PlaybackBox::stopPlaylistFlagging
void stopPlaylistFlagging()
Definition: playbackbox.h:247
TV::IsSameProgram
bool IsSameProgram(const ProgramInfo *ProgInfo) const
Definition: tv_play.cpp:10439
ProgramInfoCache::PIC_RECGROUP_CHANGED
@ PIC_RECGROUP_CHANGED
Definition: programinfocache.h:28
ProgramInfo::UpdateLastDelete
void UpdateLastDelete(bool setTime) const
Set or unset the record.last_delete field.
Definition: programinfo.cpp:3430
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:93
tv.h
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1614
RefCountHandler
Definition: referencecounterlist.h:17
ACTION_VIEWSCHEDULED
#define ACTION_VIEWSCHEDULED
Definition: tv_actions.h:31
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:102
MythCoreContext::GetMasterHostName
QString GetMasterHostName(void)
Definition: mythcorecontext.cpp:811
PlaybackBox::m_isFilling
bool m_isFilling
Definition: playbackbox.h:422
RecordingInfo::kReSearchTypeName
static const QRegularExpression kReSearchTypeName
Definition: recordinginfo.h:197
ProgramInfo::GetFilesize
virtual uint64_t GetFilesize(void) const
Definition: programinfo.cpp:6446
PlaybackBox::UpdateUIGroupList
void UpdateUIGroupList(const QStringList &groupPreferences)
Definition: playbackbox.cpp:1404
kState_None
@ kState_None
None State, this is the initial state in both TV and TVRec, it indicates that we are ready to change ...
Definition: tv.h:61
kCheckForPlaylistAction
@ kCheckForPlaylistAction
Definition: playbackboxhelper.h:26
MythUIButtonList::SetValueByData
void SetValueByData(const QVariant &data)
Definition: mythuibuttonlist.cpp:1566
mythuitext.h
mythuiprogressbar.h
PlaybackBox::setPlayGroup
void setPlayGroup(QString newPlayGroup)
Definition: playbackbox.cpp:4940
MythEvent::kMythEventMessage
static const Type kMythEventMessage
Definition: mythevent.h:79
PlaybackBox::Load
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
Definition: playbackbox.cpp:561
MythUIImage
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
DialogCompletionEvent::GetId
QString GetId()
Definition: mythdialogbox.h:52
comp_season
static int comp_season(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:131
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
ShowNotificationError
void ShowNotificationError(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
convenience utility to display error message as notification
Definition: mythnotificationcenter.cpp:1426
ACTION_PLAYBACK
#define ACTION_PLAYBACK
Definition: tv_actions.h:7
ProgramInfo::SaveBookmark
void SaveBookmark(uint64_t frame)
Clears any existing bookmark in DB and if frame is greater than 0 sets a new bookmark.
Definition: programinfo.cpp:2680
ProgramInfo::SetRecordingStatus
void SetRecordingStatus(RecStatus::Type status)
Definition: programinfo.h:584
ProgramInfo::GetHostname
QString GetHostname(void) const
Definition: programinfo.h:422
MythUIButtonList::GetItemNext
MythUIButtonListItem * GetItemNext(MythUIButtonListItem *item) const
Definition: mythuibuttonlist.cpp:1668
PlaybackBox::updateRecGroup
void updateRecGroup(MythUIButtonListItem *sel_item)
Definition: playbackbox.cpp:1456
PlaybackBox::PbbJobQueue::m_jobs
MapType m_jobs
Definition: playbackbox.h:488
PlaybackBox::~PlaybackBox
~PlaybackBox(void) override
Definition: playbackbox.cpp:477
ACTION_PAGERIGHT
#define ACTION_PAGERIGHT
Definition: tv_actions.h:12
ShowNotification
void ShowNotification(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
Definition: mythnotificationcenter.cpp:1437
mythdb.h
PlaybackBox::m_currentGroup
QString m_currentGroup
Group currently selected.
Definition: playbackbox.h:432
PlaybackBox::m_groupSelected
bool m_groupSelected
Definition: playbackbox.h:464
TV::GetRecordingGroup
QString GetRecordingGroup() const
Definition: tv_play.cpp:10423
mythrandom.h
MythUIButtonListItem::DisplayState
void DisplayState(const QString &state, const QString &name)
Definition: mythuibuttonlist.cpp:3613
wlEarlier
@ wlEarlier
Definition: programtypes.h:187
JobQueue::QueueJob
static bool QueueJob(int jobType, uint chanid, const QDateTime &recstartts, const QString &args="", const QString &comment="", QString host="", int flags=0, int status=JOB_QUEUED, QDateTime schedruntime=QDateTime())
Definition: jobqueue.cpp:507
PlaybackBox::m_artImage
std::array< MythUIImage *, kNumArtImages > m_artImage
Definition: playbackbox.h:370
MythUIComposite::ResetMap
virtual void ResetMap(const InfoMap &infoMap)
Definition: mythuicomposite.cpp:28
MythDate::as_utc
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
Definition: mythdate.cpp:28
comp_recordDate
static int comp_recordDate(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:113
PlaybackBoxHelper::GetFreeSpaceTotalMB
uint64_t GetFreeSpaceTotalMB(void) const
Definition: playbackboxhelper.cpp:418
PlaybackBox::saveRecMetadata
void saveRecMetadata(const QString &newTitle, const QString &newSubtitle, const QString &newDescription, const QString &newInetref, uint season, uint episode)
Definition: playbackbox.cpp:4800
PlaybackBox::doPlayListRandom
void doPlayListRandom()
Definition: playbackbox.cpp:3304
PlaybackBox::doPlaylistBeginUserJob2
void doPlaylistBeginUserJob2()
Definition: playbackbox.h:252
PlaybackBox::SetRecGroupPassword
void SetRecGroupPassword(const QString &newPassword)
Definition: playbackbox.cpp:4997
MythScreenType::Close
virtual void Close()
Definition: mythscreentype.cpp:383
JobQueue::ChangeJobCmds
static bool ChangeJobCmds(int jobID, int newCmds)
Definition: jobqueue.cpp:918
ScheduleCommon::customEvent
void customEvent(QEvent *event) override
Definition: schedulecommon.cpp:483
comp_programid
static int comp_programid(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:62
PlaybackBox::VIEW_CATEGORIES
@ VIEW_CATEGORIES
Definition: playbackbox.h:90
MetadataResultsDialog
Definition: mythuimetadataresults.h:10
PlaybackBox::CreateProgramInfoString
static QString CreateProgramInfoString(const ProgramInfo &pginfo)
Definition: playbackbox.cpp:3257
PlaybackBox::doPlaylistBeginFlagging
void doPlaylistBeginFlagging()
Definition: playbackbox.h:246
MythUIButtonList::MoveDown
virtual bool MoveDown(MovementUnit unit=MoveItem, uint amount=0)
Definition: mythuibuttonlist.cpp:2193
PlaybackBox::m_popupStack
MythScreenStack * m_popupStack
Definition: playbackbox.h:408
PlaybackBox::SetItemIcons
void SetItemIcons(MythUIButtonListItem *item, ProgramInfo *pginfo)
Definition: playbackbox.cpp:779
RecStatus::Tuning
@ Tuning
Definition: recordingstatus.h:22
PlaybackBox::m_previewImage
MythUIImage * m_previewImage
Definition: playbackbox.h:363
ACTION_LISTRECORDEDEPISODES
#define ACTION_LISTRECORDEDEPISODES
Definition: tv_actions.h:24
kStartTVIgnoreLastPlayPos
@ kStartTVIgnoreLastPlayPos
Definition: tv_play.h:118
RecordingInfo
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:35
PlaybackBox::DeletePopupType
DeletePopupType
Definition: playbackbox.h:99
kProbableMovie
@ kProbableMovie
Definition: metadatacommon.h:53
MythUIType::GetChild
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:138
ScheduleCommon::ShowUpcomingScheduled
virtual void ShowUpcomingScheduled(void) const
Show the upcoming recordings for this recording rule.
Definition: schedulecommon.cpp:88
MythUIButtonList::RemoveItem
void RemoveItem(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1512
mythscreenstack.h
comp_originalAirDate
static int comp_originalAirDate(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:78
PlaybackBox::setRecGroup
void setRecGroup(QString newRecGroup)
Definition: playbackbox.cpp:4867
PlaybackBox::PlayFromBeginning
void PlayFromBeginning()
Definition: playbackbox.h:154
ProgramInfoCache::GetOrdered
void GetOrdered(std::vector< ProgramInfo * > &list, bool newest_first=false)
Definition: programinfocache.cpp:315
RecordingInfo::ForgetHistory
void ForgetHistory(void)
Forget the recording of a program so it will be recorded again.
Definition: recordinginfo.cpp:1483
MythUIImage::Load
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
Definition: mythuiimage.cpp:971
PlaybackBox::m_newRecGroup
QString m_newRecGroup
Definition: playbackbox.h:399
ProgramInfo::GetRecordingID
uint GetRecordingID(void) const
Definition: programinfo.h:450
RecMetadataEdit::m_titleEdit
MythUITextEdit * m_titleEdit
Definition: playbackbox.h:593
PlaybackBox::stopPlaylistUserJob3
void stopPlaylistUserJob3()
Definition: playbackbox.h:255
PlaybackBox::kForceDeleteRecording
@ kForceDeleteRecording
Definition: playbackbox.h:103
hardwareprofile.devicelist.cat
def cat(file_name)
Definition: devicelist.py:95
PlaybackBox::getRecGroupPassword
QString getRecGroupPassword(const QString &recGroup)
Definition: playbackbox.cpp:4601
MythUIBusyDialog::Create
bool Create(void) override
Definition: mythprogressdialog.cpp:32
PlaybackBox::m_listOrder
int m_listOrder
listOrder controls the ordering of the recordings in the list
Definition: playbackbox.h:393
asZeroByte
@ asZeroByte
Definition: programtypes.h:180
ProgramInfoCache::UpdateState
UpdateState
Definition: programinfocache.h:25
comp_recordDate_rev
static int comp_recordDate_rev(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:122
PlaybackBox::doBeginTranscoding
void doBeginTranscoding()
Definition: playbackbox.h:237
PlaybackBox::m_popupMenu
MythMenu * m_popupMenu
Definition: playbackbox.h:407
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
PlaybackBox::UpdateUIRecGroupList
void UpdateUIRecGroupList(void)
Definition: playbackbox.cpp:1375
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
PlaybackBox::showViewChanger
void showViewChanger(void)
Definition: playbackbox.cpp:4401
PasswordChange::Create
bool Create(void) override
Definition: playbackbox.cpp:5160
PlaybackBox::m_playerSelectedNewShow
QStringList m_playerSelectedNewShow
Definition: playbackbox.h:456
HelpPopup
Definition: playbackbox.h:607
MythMenu::AddItem
void AddItem(const QString &title)
Definition: mythdialogbox.h:110
PlaybackBox::DeleteFlags
DeleteFlags
Definition: playbackbox.h:106
ACTION_TOGGLERECORD
#define ACTION_TOGGLERECORD
Definition: tv_actions.h:19
PlaybackBox::kForce
@ kForce
Definition: playbackbox.h:110
PlaybackBox::PbbJobQueue::kInvalidateTimeMs
static constexpr std::chrono::milliseconds kInvalidateTimeMs
Definition: playbackbox.h:483
MythUIProgressBar::SetUsed
void SetUsed(int value)
Definition: mythuiprogressbar.cpp:72
PreviewGeneratorQueue::RemoveListener
static void RemoveListener(QObject *listener)
Stop receiving notifications when a preview event is generated.
Definition: previewgeneratorqueue.cpp:205
PlaybackBox::ItemVisible
void ItemVisible(MythUIButtonListItem *item)
Definition: playbackbox.cpp:1033
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
MythScreenStack
Definition: mythscreenstack.h:16
PlaybackBox::ClearBookmark
void ClearBookmark()
Definition: playbackbox.cpp:2224
PlaybackBox::updateGroupInfo
void updateGroupInfo(const QString &groupname, const QString &grouplabel)
Definition: playbackbox.cpp:651
mythdbcon.h
comp_recordDate_rev_less_than
static bool comp_recordDate_rev_less_than(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:189
PasswordChange::m_oldPasswordEdit
MythUITextEdit * m_oldPasswordEdit
Definition: playbackbox.h:563
PlaybackBox::doJobQueueJob
void doJobQueueJob(int jobType, int jobFlags=0)
Definition: playbackbox.cpp:3356
PlaybackBox::ViewTitleSort
ViewTitleSort
Definition: playbackbox.h:81
PlaybackBox::m_menuDialog
MythDialogBox * m_menuDialog
Definition: playbackbox.h:406
comp_originalAirDate_rev_less_than
static bool comp_originalAirDate_rev_less_than(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:171
PlaybackBox::m_viewMask
ViewMask m_viewMask
Definition: playbackbox.h:402
MythUIType::SetCanTakeFocus
void SetCanTakeFocus(bool set=true)
Set whether this widget can take focus.
Definition: mythuitype.cpp:362
RecordingRule
Internal representation of a recording rule, mirrors the record table.
Definition: recordingrule.h:28
PlaybackBox::PlayFromLastPlayPos
void PlayFromLastPlayPos()
Definition: playbackbox.h:156
PlaybackBox::PlayFromBookmark
void PlayFromBookmark()
Definition: playbackbox.h:152
PlaybackBox::PlaybackBox
PlaybackBox(MythScreenStack *parent, const QString &name, TV *player=nullptr, bool showTV=false)
Definition: playbackbox.cpp:386
ProgramInfo::SetEditing
void SetEditing(bool editing)
Definition: programinfo.h:550
MythUIButtonListItem::parent
MythUIButtonList * parent() const
Definition: mythuibuttonlist.cpp:3674
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
comp_season_less_than
static bool comp_season_less_than(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:195
PlaybackBox::toggleCategoryView
void toggleCategoryView(bool setOn)
Definition: playbackbox.h:215
RecMetadataEdit::m_seasonSpin
MythUISpinBox * m_seasonSpin
Definition: playbackbox.h:597
MythUITextEdit
A text entry and edit widget.
Definition: mythuitextedit.h:34
PlaybackBox::m_player
TV * m_player
Definition: playbackbox.h:455
comp_programid_rev
static int comp_programid_rev(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:70
PasswordChange::SendResult
void SendResult(void)
Definition: playbackbox.cpp:5200
PlaybackBox::ShowDeletePopup
void ShowDeletePopup(DeletePopupType type)
Definition: playbackbox.cpp:2510
GuessLookupType
LookupType GuessLookupType(ProgramInfo *pginfo)
Definition: metadatafactory.cpp:645
PlaybackBox::ScheduleUpdateUIList
void ScheduleUpdateUIList(void)
Definition: playbackbox.cpp:4385
PlaybackBox::m_watchListMaxAge
int m_watchListMaxAge
add 1 to the Watch List scord up to this many days
Definition: playbackbox.h:387
ACTION_PREVRECORDED
#define ACTION_PREVRECORDED
Definition: tv_actions.h:32
ScheduleCommon::ShowGuide
virtual void ShowGuide(void) const
Show the program guide.
Definition: schedulecommon.cpp:134
PlaybackBox::ShowAllRecordings
void ShowAllRecordings()
Definition: playbackbox.cpp:3532
PlaybackBox::doPlaylistWatchedSetOn
void doPlaylistWatchedSetOn()
Definition: playbackbox.h:266
ProgramInfo::IsPathSet
bool IsPathSet(void) const
Definition: programinfo.h:358
PlaybackBox::m_playingSomething
bool m_playingSomething
playingSomething is set to true iff a full screen recording is playing
Definition: playbackbox.h:442
ProgramInfo::IsInUsePlaying
bool IsInUsePlaying(void) const
Definition: programinfo.h:480
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
playgroup.h
ProgramInfoCache::empty
bool empty(void) const
Definition: programinfocache.h:49
MythDialogBox::Closed
void Closed(QString, int)
ChangeView::m_parentScreen
PlaybackBox * m_parentScreen
Definition: playbackbox.h:540
PlaybackBox::DeleteForgetHistory
void DeleteForgetHistory(void)
Definition: playbackbox.h:198
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:45
mythuistatetype.h
comp_recordDate_less_than
static bool comp_recordDate_less_than(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:183
RecMetadataEdit::PerformQuery
void PerformQuery(void)
Definition: playbackbox.cpp:5295
MythUIStateType::Reset
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuistatetype.cpp:197
PlaybackBox::PbbJobQueue::IsJobRunning
bool IsJobRunning(int jobType, uint chanid, const QDateTime &recstartts)
Definition: playbackbox.cpp:5524
RecMetadataEdit::m_metadataFactory
MetadataFactory * m_metadataFactory
Definition: playbackbox.h:604
construct_sort_title
static QString construct_sort_title(QString title, const QString &sortTitle, PlaybackBox::ViewMask viewmask, PlaybackBox::ViewTitleSort sortType, int recpriority)
Definition: playbackbox.cpp:219
MythUITextEdit::GetText
QString GetText(void) const
Definition: mythuitextedit.h:50
MythUIButtonList::SetSearchFields
void SetSearchFields(const QString &fields)
Definition: mythuibuttonlist.h:256
PlaybackBox::IsUsageUIVisible
bool IsUsageUIVisible(void) const
Definition: playbackbox.cpp:1313
PlaybackBox::doPlaylistExpireSetting
void doPlaylistExpireSetting(bool turnOn)
Definition: playbackbox.cpp:4746
JOB_LIST_ALL
@ JOB_LIST_ALL
Definition: jobqueue.h:67
recordingtypes.h
MythUIButtonList::MoveItem
@ MoveItem
Definition: mythuibuttonlist.h:206
MythUIImage::Reset
void Reset(void) override
Reset the image back to the default defined in the theme.
Definition: mythuiimage.cpp:644
RecMetadataEdit::result
void result(const QString &, const QString &, const QString &, const QString &, uint, uint)
PlaybackBox::DeleteForce
void DeleteForce(void)
Definition: playbackbox.h:199
PlaybackBox::passwordClosed
void passwordClosed(void)
Definition: playbackbox.cpp:644
PlaybackBox::m_needUpdate
bool m_needUpdate
Does the recording list need to be refilled.
Definition: playbackbox.h:445
ProgramInfo::GetRecordingEndTime
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:413
PlaybackBox::checkPassword
void checkPassword(const QString &password)
Definition: playbackbox.cpp:634
PlaybackBox::stopPlaylistUserJob2
void stopPlaylistUserJob2()
Definition: playbackbox.h:253
ProgramInfo::GetProgramFlags
uint32_t GetProgramFlags(void) const
Definition: programinfo.h:474
ProgramInfo::GetRecordingGroup
QString GetRecordingGroup(void) const
Definition: programinfo.h:420
MythTextInputDialog::haveResult
void haveResult(QString)
PlaybackBox::askDelete
void askDelete()
Definition: playbackbox.cpp:3445
PlaybackBox::ItemLoaded
void ItemLoaded(MythUIButtonListItem *item)
Definition: playbackbox.cpp:921
ProgramInfo::IsLastPlaySet
bool IsLastPlaySet(void) const
Definition: programinfo.h:485
MythUISpinBox::SetRange
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.
Definition: mythuispinbox.cpp:26
mythuibuttonlist.h
PasswordChange
Definition: playbackbox.h:544
kNormalAutoExpire
@ kNormalAutoExpire
Definition: programtypes.h:194
PlaybackBox::doPlaylistBeginTranscoding
void doPlaylistBeginTranscoding()
Definition: playbackbox.h:243
PlaybackBoxHelper::UndeleteRecording
void UndeleteRecording(uint recordingID)
Definition: playbackboxhelper.cpp:393
kStartTVInPlayList
@ kStartTVInPlayList
Definition: tv_play.h:114
PlaybackBox::m_currentMap
InfoMap m_currentMap
Definition: playbackbox.h:373
mythuiimage.h
MythUIButtonList::GetCount
int GetCount() const
Definition: mythuibuttonlist.cpp:1679
ScheduleCommon::ShowDetails
virtual void ShowDetails(void) const
Show the Program Details screen.
Definition: schedulecommon.cpp:27
PlaybackBox::m_helper
PlaybackBoxHelper m_helper
Main helper thread.
Definition: playbackbox.h:458
PlaybackBox::ShowMenu
void ShowMenu(void) override
Definition: playbackbox.cpp:2881
mythprogressdialog.h
MythEvent::Message
const QString & Message() const
Definition: mythevent.h:65
PlaybackBox::RemoveProgram
void RemoveProgram(uint recordingID, bool forgetHistory, bool forceMetadataDelete)
Definition: playbackbox.cpp:2463
VideoArtworkType
VideoArtworkType
Definition: metadataimagehelper.h:10
PlaybackBox::stopPlaylistJobQueueJob
void stopPlaylistJobQueueJob(int jobType)
Definition: playbackbox.cpp:3420
PlaybackBox::stopPlaylistTranscoding
void stopPlaylistTranscoding()
Definition: playbackbox.h:245
PlaybackBox::m_watchGroupName
QString m_watchGroupName
Definition: playbackbox.h:400
kCheckForPlayAction
@ kCheckForPlayAction
Definition: playbackboxhelper.h:25
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:405
RecMetadataEdit::m_descriptionEdit
MythUITextEdit * m_descriptionEdit
Definition: playbackbox.h:595
MetadataFactoryNoResult
Definition: metadatafactory.h:50
TV::StartTV
static bool StartTV(ProgramInfo *TVRec, uint Flags, const ChannelInfoList &Selection=ChannelInfoList())
Start playback of media.
Definition: tv_play.cpp:287
PlaybackBox::playSelectedPlaylist
void playSelectedPlaylist(bool Random)
Definition: playbackbox.cpp:2104
MythUIButtonList::GetItemByData
MythUIButtonListItem * GetItemByData(const QVariant &data)
Definition: mythuibuttonlist.cpp:1708
ProgramInfo::IsWatched
bool IsWatched(void) const
Definition: programinfo.h:486
m_viewMaskToggle
static PlaybackBox::ViewMask m_viewMaskToggle(PlaybackBox::ViewMask mask, PlaybackBox::ViewMask toggle)
Definition: playbackbox.cpp:210
PlaybackBox::showRecGroupPasswordChanger
void showRecGroupPasswordChanger()
Definition: playbackbox.cpp:4974
ScheduleCommon::EditScheduled
virtual void EditScheduled(void)
Creates a dialog for editing the recording schedule.
Definition: schedulecommon.cpp:168
push_onto_del
static void push_onto_del(QStringList &list, const ProgramInfo &pginfo)
Definition: playbackbox.cpp:343
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
kCheckForMenuAction
@ kCheckForMenuAction
Definition: playbackboxhelper.h:24
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:110
ChangeView::m_viewMask
int m_viewMask
Definition: playbackbox.h:541
programtypes.h
PlaybackBox::kNumArtImages
constexpr static int kNumArtImages
Definition: playbackbox.h:369
MetadataLookup
Definition: metadatacommon.h:87
MythUICheckBox::toggled
void toggled(bool)
PlaybackBox::doBeginUserJob1
void doBeginUserJob1()
Definition: playbackbox.h:239
PlaybackBox::Delete
void Delete()
Definition: playbackbox.h:197
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
sLocation
static const QString sLocation
Definition: playbackbox.cpp:60
MythUIButtonListItem::SetText
void SetText(const QString &text, const QString &name="", const QString &state="")
Definition: mythuibuttonlist.cpp:3319
ProgramInfo::IsPreserved
bool IsPreserved(void) const
Definition: programinfo.h:488
MythObservable::addListener
void addListener(QObject *listener)
Add a listener to the observable.
Definition: mythobservable.cpp:38
PlayGroup::GetNames
static QStringList GetNames(void)
Definition: playgroup.cpp:210
PlaybackBox::Create
bool Create(void) override
Definition: playbackbox.cpp:496
ChangeView::SaveChanges
void SaveChanges(void)
Definition: playbackbox.cpp:5152
ChangeView::save
void save()
asNotYetAvailable
@ asNotYetAvailable
Definition: programtypes.h:177
MythUIButtonList::GetItemPos
int GetItemPos(MythUIButtonListItem *item) const
Definition: mythuibuttonlist.cpp:1722
PlaybackBox::m_doToggleMenu
bool m_doToggleMenu
Definition: playbackbox.h:410
ProgramInfo::GetInetRef
QString GetInetRef(void) const
Definition: programinfo.h:441
CheckAvailabilityType
CheckAvailabilityType
Definition: playbackboxhelper.h:22
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
ProgramInfoCache::PIC_MARK_CHANGED
@ PIC_MARK_CHANGED
Definition: programinfocache.h:27
MetadataFactoryNoResult::kEventType
static const Type kEventType
Definition: metadatafactory.h:65
PlaybackBox::m_recGroups
QStringList m_recGroups
Definition: playbackbox.h:424
MythUISpinBox::SetValue
void SetValue(int val) override
Definition: mythuispinbox.h:26
PlaybackBox::doPlaylistBeginLookup
void doPlaylistBeginLookup()
Definition: playbackbox.h:248
PlaybackBox::m_watchGroupLabel
QString m_watchGroupLabel
Definition: playbackbox.h:401
MythUITextEdit::SetText
void SetText(const QString &text, bool moveCursor=true)
Definition: mythuitextedit.cpp:198
PlaybackBox::m_groupList
MythUIButtonList * m_groupList
Definition: playbackbox.h:358
ProgramInfoCache::PIC_NONE
@ PIC_NONE
Definition: programinfocache.h:26
playbackbox.h
ScheduleCommon::ShowPrevious
virtual void ShowPrevious(void) const
Show the previous recordings for this recording rule.
Definition: schedulecommon.cpp:250
GroupSelector::AcceptItem
void AcceptItem(MythUIButtonListItem *item)
Definition: playbackbox.cpp:5054
PlaybackBox::m_ncLock
QMutex m_ncLock
Definition: playbackbox.h:451
PlaybackBox::kForgetHistory
@ kForgetHistory
Definition: playbackbox.h:109
JobQueue::GetJobsInQueue
static int GetJobsInQueue(QMap< int, JobQueueEntry > &jobs, int findJobs=JOB_LIST_NOT_DONE)
Definition: jobqueue.cpp:1281
PlaybackBox::kAllRemaining
@ kAllRemaining
Definition: playbackbox.h:112
mythdate.h
PlaybackBox::Init
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
Definition: playbackbox.cpp:567
PlaybackBox::kIgnore
@ kIgnore
Definition: playbackbox.h:111
kArtworkCoverart
@ kArtworkCoverart
Definition: metadataimagehelper.h:11
PlaybackBox::createPlaylistMenu
MythMenu * createPlaylistMenu()
Definition: playbackbox.cpp:2663
MythUIProgressBar::SetTotal
void SetTotal(int value)
Definition: mythuiprogressbar.cpp:78
ProgramInfo::SetPathname
void SetPathname(const QString &pn)
Definition: programinfo.cpp:2449
kLookupSearch
@ kLookupSearch
Definition: metadatacommon.h:28
PasswordChange::OldPasswordChanged
void OldPasswordChanged(void)
Definition: playbackbox.cpp:5192
PlaybackBox::m_recordedProgress
MythUIProgressBar * m_recordedProgress
Definition: playbackbox.h:365
RecMetadataEdit::m_queryButton
MythUIButton * m_queryButton
Definition: playbackbox.h:600
programinfo.h
PlaybackBox::m_playListPlay
QList< uint > m_playListPlay
list of items being played.
Definition: playbackbox.h:437
PlaybackBox::TitleSortRecPriority
@ TitleSortRecPriority
Definition: playbackbox.h:83
RecMetadataEdit::m_busyPopup
MythUIBusyDialog * m_busyPopup
Definition: playbackbox.h:599
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:391
kArtworkFanart
@ kArtworkFanart
Definition: metadataimagehelper.h:12
MythUIButtonList::itemLoaded
void itemLoaded(MythUIButtonListItem *item)
ScheduleCommon::EditCustom
virtual void EditCustom(void)
Creates a dialog for creating a custom recording rule.
Definition: schedulecommon.cpp:204
JobQueue::IsJobQueuedOrRunning
static bool IsJobQueuedOrRunning(int jobType, uint chanid, const QDateTime &recstartts)
Definition: jobqueue.cpp:1097
mythlogging.h
ProgramInfo::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:451
PlaybackBox::doPlayList
void doPlayList(void)
Definition: playbackbox.cpp:3298
RecMetadataEdit::m_inetrefEdit
MythUITextEdit * m_inetrefEdit
Definition: playbackbox.h:596
JOB_USERJOB3
@ JOB_USERJOB3
Definition: jobqueue.h:86
MetadataLookup::GetEpisode
uint GetEpisode() const
Definition: metadatacommon.h:315
MetadataLookup::GetDescription
QString GetDescription() const
Definition: metadatacommon.h:312
PlaybackBox::VIEW_LIVETVGRP
@ VIEW_LIVETVGRP
Definition: playbackbox.h:94
PlaybackBox::updateRecList
void updateRecList(MythUIButtonListItem *sel_item)
Definition: playbackbox.cpp:1478
MythCoreContext::GetQLocale
QLocale GetQLocale(void)
Definition: mythcorecontext.cpp:1882
PlaybackBox::doPlaylistBeginUserJob3
void doPlaylistBeginUserJob3()
Definition: playbackbox.h:254
PlaybackBox::stopPlaylistLookup
void stopPlaylistLookup()
Definition: playbackbox.h:249
PlaybackBox::PbbJobQueue::Update
void Update()
Definition: playbackbox.cpp:5493
ACTION_1
static constexpr const char * ACTION_1
Definition: mythuiactions.h:5
PlaybackBox::bannerLoad
void bannerLoad(void)
Definition: playbackbox.cpp:2500
MythUIButtonList::itemClicked
void itemClicked(MythUIButtonListItem *item)
PlaybackBox::toggleWatchedView
void toggleWatchedView(bool setOn)
Definition: playbackbox.h:220
MythMainWindow::TranslateKeyPress
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
Definition: mythmainwindow.cpp:1111
RecMetadataEdit::OnSearchListSelection
void OnSearchListSelection(const RefCountHandler< MetadataLookup > &lookup)
Definition: playbackbox.cpp:5363
pbs
Definition: pbs.py:1
PlaybackBox::ItemSelected
void ItemSelected(MythUIButtonListItem *item)
Definition: playbackbox.h:143
PlaybackBox::doPlaylistAllowRerecord
void doPlaylistAllowRerecord()
Definition: playbackbox.cpp:3337
PlaybackBox::groupSelectorClosed
void groupSelectorClosed(void)
Definition: playbackbox.cpp:4551
MythUIButtonList::GetCurrentPos
int GetCurrentPos() const
Definition: mythuibuttonlist.h:240
tv_actions.h
PlaybackBox::createTranscodingProfilesMenu
MythMenu * createTranscodingProfilesMenu()
Definition: playbackbox.cpp:3068
MythUIProgressBar::Set
void Set(int start, int total, int used)
Definition: mythuiprogressbar.cpp:56
MythUIProgressBar
Progress bar widget.
Definition: mythuiprogressbar.h:12
PlaybackBox::PbbJobQueue::IsJobQueued
bool IsJobQueued(int jobType, uint chanid, const QDateTime &recstartts)
Definition: playbackbox.cpp:5510
JOB_METADATA
@ JOB_METADATA
Definition: jobqueue.h:80
hardwareprofile.config.p
p
Definition: config.py:33
PlaybackBoxHelper::GetPreviewImage
QString GetPreviewImage(const ProgramInfo &pginfo, bool check_availability=true)
Definition: playbackboxhelper.cpp:480
PlaybackBox::createPlayFromMenu
MythMenu * createPlayFromMenu()
Definition: playbackbox.cpp:2914
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:115
PlaybackBox::UpdateUILists
bool UpdateUILists(void)
Definition: playbackbox.cpp:1664
PlaybackBox::saveViewChanges
void saveViewChanges(void)
Definition: playbackbox.cpp:4416
RefCountedList< MetadataLookup >
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:166
comp_originalAirDate_less_than
static bool comp_originalAirDate_less_than(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:165
PlaybackBox::processNetworkControlCommands
void processNetworkControlCommands(void)
Definition: playbackbox.cpp:3705
MythUIButtonList::LoadInBackground
void LoadInBackground(int start=0, int pageSize=20)
Definition: mythuibuttonlist.cpp:2805
menu
static MythThemedMenu * menu
Definition: mythtv-setup.cpp:58
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:362
ProgramInfo::GetDescription
QString GetDescription(void) const
Definition: programinfo.h:366
compat.h
kArtworkBanner
@ kArtworkBanner
Definition: metadataimagehelper.h:13
kMetadataRecording
@ kMetadataRecording
Definition: metadatacommon.h:44
MythUISpinBox::GetIntValue
int GetIntValue(void) const override
Definition: mythuispinbox.h:33
MythDialogBox::Create
bool Create(void) override
Definition: mythdialogbox.cpp:127
PlaybackBox::DisplayPopupMenu
void DisplayPopupMenu(void)
Definition: playbackbox.cpp:2863
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:225
PlaybackBoxHelper::DeleteRecordings
void DeleteRecordings(const QStringList &list)
Definition: playbackboxhelper.cpp:387
GroupSelector::m_selected
QString m_selected
Definition: playbackbox.h:518
asPendingDelete
@ asPendingDelete
Definition: programtypes.h:178
MythCoreContext::GetDurSetting
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
Definition: mythcorecontext.h:168
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:203
hardwareprofile.scan.rating
def rating(profile, smoonURL, gate)
Definition: scan.py:37
RecordingRule::m_autoExpire
bool m_autoExpire
Definition: recordingrule.h:126
PlaybackBox::ShowRecGroupChangerUsePlaylist
void ShowRecGroupChangerUsePlaylist(void)
Definition: playbackbox.h:179
RecStatus::Failing
@ Failing
Definition: recordingstatus.h:18
PlaybackBox::HandleRecordingAddEvent
void HandleRecordingAddEvent(const ProgramInfo &evinfo)
Definition: playbackbox.cpp:4362
ProgramInfo::HasCutlist
bool HasCutlist(void) const
Definition: programinfo.h:483
ProgramInfoCache::ScheduleLoad
void ScheduleLoad(bool updateUI=true)
Definition: programinfocache.cpp:64
MythUIButton
A single button widget.
Definition: mythuibutton.h:21
PlaybackBox::showGroupFilter
void showGroupFilter()
Definition: playbackbox.cpp:4425
ProgramInfoCache::Update
ProgramInfoCache::UpdateStates Update(const ProgramInfo &pginfo)
Updates a ProgramInfo in the cache.
Definition: programinfocache.cpp:196
PlaybackBox::PbbJobQueue::IsJobQueuedOrRunning
bool IsJobQueuedOrRunning(int jobType, uint chanid, const QDateTime &recstartts)
Definition: playbackbox.cpp:5538
stringutil.h
JOB_USERJOB1
@ JOB_USERJOB1
Definition: jobqueue.h:84
kManualSearch
@ kManualSearch
Definition: recordingtypes.h:84
PlaybackBox::HandlePreviewEvent
void HandlePreviewEvent(const QStringList &list)
Updates the UI properties for a new preview file.
Definition: playbackbox.cpp:1076
PlaybackBox::toggleTitleView
void toggleTitleView(bool setOn)
Definition: playbackbox.h:214
AutoExpireType
AutoExpireType
Definition: programtypes.h:192
MetadataLookup::GetSubtitle
QString GetSubtitle() const
Definition: metadatacommon.h:310
MythUIComposite::SetTextFromMap
virtual void SetTextFromMap(const InfoMap &infoMap)
Definition: mythuicomposite.cpp:9
ScheduleCommon
Definition: schedulecommon.h:15
MythDate::kDateShort
@ kDateShort
Default local time.
Definition: mythdate.h:20
JOB_COMMFLAG
@ JOB_COMMFLAG
Definition: jobqueue.h:79
PlaybackBox::extract_commflag_state
QString extract_commflag_state(const ProgramInfo &pginfo)
Definition: playbackbox.cpp:312
ProgramInfoCache::GetRecordingInfo
ProgramInfo * GetRecordingInfo(uint recordingID) const
Definition: programinfocache.cpp:326
comp_season_rev
static int comp_season_rev(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:142
PlaybackBox::deleteSelected
void deleteSelected(MythUIButtonListItem *item)
Definition: playbackbox.cpp:2245
ProgramInfo::toString
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
Definition: programinfo.cpp:1945
PlaybackBox::fillRecGroupPasswordCache
void fillRecGroupPasswordCache(void)
Definition: playbackbox.cpp:4606
HelpPopup::Create
bool Create(void) override
Definition: playbackbox.cpp:5435
ProgramInfoCache::Refresh
void Refresh(void)
Refreshed the cache.
Definition: programinfocache.cpp:160
PasswordChange::m_oldPassword
QString m_oldPassword
Definition: playbackbox.h:567
PlaybackBox::togglePreserveEpisode
void togglePreserveEpisode()
Definition: playbackbox.cpp:3623
JOB_USERJOB4
@ JOB_USERJOB4
Definition: jobqueue.h:87
MConcurrent::run
void run(const QString &name, Class *object, void(Class::*fn)())
Definition: mconcurrent.h:137
PreviewGeneratorQueue::AddListener
static void AddListener(QObject *listener)
Request notifications when a preview event is generated.
Definition: previewgeneratorqueue.cpp:189
playbackboxlistitem.h
PlaybackBox::toggleSearchView
void toggleSearchView(bool setOn)
Definition: playbackbox.h:218
PlaybackBox::createPlaylistStorageMenu
MythMenu * createPlaylistStorageMenu()
Definition: playbackbox.cpp:2702
kStartTVIgnoreProgStart
@ kStartTVIgnoreProgStart
Definition: tv_play.h:117
MetadataFactoryMultiResult::kEventType
static const Type kEventType
Definition: metadatafactory.h:29
PlaybackBox::PbbJobQueue::m_lastUpdated
QDateTime m_lastUpdated
Definition: playbackbox.h:485
MythUITextEdit::SetPassword
void SetPassword(bool isPassword)
Definition: mythuitextedit.h:53
kJobs
static const std::array< const int, kMaxJobs > kJobs
Definition: playbackbox.cpp:2988
PlaybackBox::DeleteIgnoreAllRemaining
void DeleteIgnoreAllRemaining(void)
Definition: playbackbox.h:203
kArtworkCoverTimeout
static constexpr uint8_t kArtworkCoverTimeout
Definition: playbackbox.h:59
ProgramInfo::GetAudioProperties
uint GetAudioProperties(void) const
Definition: programinfo.h:501
PlaybackBox::doClearPlaylist
void doClearPlaylist()
Definition: playbackbox.cpp:3279
PlaybackBox::doBeginUserJob4
void doBeginUserJob4()
Definition: playbackbox.h:242
MythUIBusyDialog
Definition: mythprogressdialog.h:36
MythUIType::SetEnabled
void SetEnabled(bool enable)
Definition: mythuitype.cpp:1128
kState_WatchingLiveTV
@ kState_WatchingLiveTV
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
Definition: tv.h:66
PasswordChange::m_newPasswordEdit
MythUITextEdit * m_newPasswordEdit
Definition: playbackbox.h:564
RecMetadataEdit::m_episodeSpin
MythUISpinBox * m_episodeSpin
Definition: playbackbox.h:598
MythUIButtonList::SetLCDTitles
void SetLCDTitles(const QString &title, const QString &columnList="")
Definition: mythuibuttonlist.cpp:3083
StringUtil::intToPaddedString
QString intToPaddedString(int n, int width=2)
Creates a zero padded string representation of an integer.
Definition: stringutil.h:27
ProgramInfo::GetPlaybackGroup
QString GetPlaybackGroup(void) const
Definition: programinfo.h:421
comp_originalAirDate_rev
static int comp_originalAirDate_rev(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:91
PlaybackBox::kStopRecording
@ kStopRecording
Definition: playbackbox.h:102
RecMetadataEdit::SaveChanges
void SaveChanges(void)
Definition: playbackbox.cpp:5273
RecMetadataEdit
Definition: playbackbox.h:570
kStartTVIgnoreBookmark
@ kStartTVIgnoreBookmark
Definition: tv_play.h:116
PlaybackBox::setGroupFilter
void setGroupFilter(const QString &newRecGroup)
Definition: playbackbox.cpp:4562
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3715
comp_recpriority2
static int comp_recpriority2(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:104
PlaybackBox::m_firstGroup
bool m_firstGroup
Definition: playbackbox.h:462
PlaybackBox::doPlaylistExpireSetOff
void doPlaylistExpireSetOff()
Definition: playbackbox.h:264
ProgramInfo::SetFilesize
virtual void SetFilesize(uint64_t sz)
Definition: programinfo.cpp:6405
PlaybackBox::m_progsInDB
int m_progsInDB
total number of recordings in DB
Definition: playbackbox.h:421
PlaybackBox::PlaylistDelete
void PlaylistDelete(bool forgetHistory=false)
Definition: playbackbox.cpp:3455
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
PlaybackBox::m_recGroupIdx
int m_recGroupIdx
Definition: playbackbox.h:426
extract_one_del
static bool extract_one_del(QStringList &list, uint &recordingID)
Definition: playbackbox.cpp:351
extract_main_state
static QString extract_main_state(const ProgramInfo &pginfo, const TV *player)
Definition: playbackbox.cpp:265
MythUICheckBox
A checkbox widget supporting three check states - on,off,half and two conditions - selected and unsel...
Definition: mythuicheckbox.h:15
kDisableAutoExpire
@ kDisableAutoExpire
Definition: programtypes.h:193
FilterNone
@ FilterNone
Definition: mythuitextedit.h:21
ProgramInfo::i18n
static QString i18n(const QString &msg)
Translations for play,recording, & storage groups +.
Definition: programinfo.cpp:5477
MetadataFactoryMultiResult
Definition: metadatafactory.h:20
PlaybackBox::popupClosed
void popupClosed(const QString &which, int result)
Definition: playbackbox.cpp:2319
ChangeView::Create
bool Create(void) override
Definition: playbackbox.cpp:5070
PlaybackBox::m_recGroupPwCache
QMap< QString, QString > m_recGroupPwCache
Definition: playbackbox.h:415
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:916
MythUIButtonList::itemVisible
void itemVisible(MythUIButtonListItem *item)
PlaybackBox::VIEW_SEARCHES
@ VIEW_SEARCHES
Definition: playbackbox.h:93
PlaybackBox::m_titleList
QStringList m_titleList
list of pages
Definition: playbackbox.h:419
MythUIButtonListItem::SetProgress2
void SetProgress2(int start, int total, int used)
Definition: mythuibuttonlist.cpp:3603
save_position
static bool save_position(const MythUIButtonList *groupList, const MythUIButtonList *recordingList, QStringList &groupSelPref, QStringList &itemSelPref, QStringList &itemTopPref)
Definition: playbackbox.cpp:1530
ProgramInfo::GetOriginalAirDate
QDate GetOriginalAirDate(void) const
Definition: programinfo.h:432
MetadataFactory
Definition: metadatafactory.h:85
PlaybackBox::ChangeView
friend class ChangeView
Definition: playbackbox.h:65
ProgramInfo::SaveAutoExpire
void SaveAutoExpire(AutoExpireType autoExpire, bool updateDelete=false)
Set "autoexpire" field in "recorded" table to "autoExpire".
Definition: programinfo.cpp:3404
PlaybackBox::showMetadataEditor
void showMetadataEditor()
Definition: playbackbox.cpp:4780
MetadataLookup::GetSeason
uint GetSeason() const
Definition: metadatacommon.h:314
kState_WatchingRecording
@ kState_WatchingRecording
Watching Recording is the state for when we are watching an in progress recording,...
Definition: tv.h:83
PlaybackBox::m_recGroupsLock
QMutex m_recGroupsLock
Definition: playbackbox.h:425
PlaybackBox::showIconHelp
void showIconHelp()
Definition: playbackbox.cpp:4391
PlaybackBox::coverartLoad
void coverartLoad(void)
Definition: playbackbox.cpp:2505
PlaybackBox::toggleAutoExpire
void toggleAutoExpire()
Definition: playbackbox.cpp:3605
PlaybackBox::doBeginUserJob2
void doBeginUserJob2()
Definition: playbackbox.h:240
PlaybackBox::selected
void selected(MythUIButtonListItem *item)
Definition: playbackbox.cpp:2311
ProgramInfo::GetVideoProperties
uint GetVideoProperties(void) const
Definition: programinfo.h:499
PlaybackBox::m_jobQueue
class PlaybackBox::PbbJobQueue m_jobQueue
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
MythUIButtonListItem::SetTextFromMap
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
Definition: mythuibuttonlist.cpp:3338
ProgramInfoCache::WaitForLoadToComplete
void WaitForLoadToComplete(void) const
Definition: programinfocache.cpp:143
PlaybackBox::StopSelected
void StopSelected(void)
Definition: playbackbox.cpp:2238
PlaybackBox::createPlaylistJobMenu
MythMenu * createPlaylistJobMenu()
Definition: playbackbox.cpp:2720
ProgramInfoCache::IsLoadInProgress
bool IsLoadInProgress(void) const
Definition: programinfocache.cpp:137
MythDate::kSimplify
@ kSimplify
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:26
PlaybackBox::m_curGroupPassword
QString m_curGroupPassword
Definition: playbackbox.h:398
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:910
MythUIButtonListItem::GetText
QString GetText(const QString &name="") const
Definition: mythuibuttonlist.cpp:3368
kMaxJobs
static constexpr size_t kMaxJobs
Definition: playbackbox.h:55
AutoDeleteDeque< ProgramInfo * >
mythuispinbox.h
PlaybackBox::ShowActionPopup
void ShowActionPopup(const ProgramInfo &pginfo)
Definition: playbackbox.cpp:3125
PlaybackBox::TitleSortAlphabetical
@ TitleSortAlphabetical
Definition: playbackbox.h:82
PlaybackBox::UpdateUIListItem
void UpdateUIListItem(ProgramInfo *pginfo, bool force_preview_reload)
Definition: playbackbox.cpp:748
PlaybackBox::m_artTimer
std::array< QTimer *, kNumArtImages > m_artTimer
Definition: playbackbox.h:371
PlaybackBox::toggleWatchListView
void toggleWatchListView(bool setOn)
Definition: playbackbox.h:217
RecMetadataEdit::RecMetadataEdit
RecMetadataEdit(MythScreenStack *lparent, ProgramInfo *pginfo)
Definition: playbackbox.cpp:5208
ProgramList
AutoDeleteDeque< ProgramInfo * > ProgramList
Definition: programinfo.h:31
PlaybackBox::doPlaylistWatchedSetting
void doPlaylistWatchedSetting(bool turnOn)
Definition: playbackbox.cpp:4763
MetadataResultsDialog::haveResult
void haveResult(RefCountHandler< MetadataLookup >)
recordinginfo.h
kLiveTVAutoExpire
@ kLiveTVAutoExpire
Definition: programtypes.h:196
std::chrono::days
duration< CHRONO_TYPE, ratio< 86400 > > days
Definition: mythchrono.h:25
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:373
MythUIButtonListItem::SetFontState
void SetFontState(const QString &state, const QString &name="")
Definition: mythuibuttonlist.cpp:3462
ProgramInfo::GetEpisode
uint GetEpisode(void) const
Definition: programinfo.h:368
MythMenu
Definition: mythdialogbox.h:99
MetadataFactorySingleResult
Definition: metadatafactory.h:32
ProgramInfo::QueryAutoExpire
AutoExpireType QueryAutoExpire(void) const
Returns "autoexpire" field from "recorded" table.
Definition: programinfo.cpp:3459
PlaybackBox::doPlaylistBeginUserJob1
void doPlaylistBeginUserJob1()
Definition: playbackbox.h:250
GroupSelector::result
void result(QString)
PlaybackBox::VIEW_WATCHED
@ VIEW_WATCHED
Definition: playbackbox.h:96
ProgramInfo::kTitleSubtitle
@ kTitleSubtitle
Definition: programinfo.h:513
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
RecordingRule::LoadTemplate
bool LoadTemplate(const QString &title, const QString &category="Default", const QString &categoryType="Default")
Definition: recordingrule.cpp:278
RecMetadataEdit::m_popupStack
MythScreenStack * m_popupStack
Definition: playbackbox.h:603
kUnknownVideo
@ kUnknownVideo
Definition: metadatacommon.h:54
MythUIText
All purpose text widget, displays a text string.
Definition: mythuitext.h:28
MythScreenType::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythscreentype.cpp:401
MetadataFactorySingleResult::kEventType
static const Type kEventType
Definition: metadatafactory.h:47
PlaybackBox::stopPlaylistUserJob4
void stopPlaylistUserJob4()
Definition: playbackbox.h:257
PlaybackBox::PlayX
void PlayX(const ProgramInfo &pginfo, bool ignoreBookmark, bool ignoreProgStart, bool ignoreLastPlayPos, bool underNetworkControl)
Definition: playbackbox.cpp:2202
LookupType
LookupType
Definition: metadatacommon.h:50
RecStatus::Recording
@ Recording
Definition: recordingstatus.h:30
PlaybackBox::m_previewTokens
QSet< QString > m_previewTokens
Outstanding preview image requests.
Definition: playbackbox.h:460
PlaybackBox::changeProfileAndTranscode
void changeProfileAndTranscode(int id)
Definition: playbackbox.cpp:3110
asAvailable
@ asAvailable
Definition: programtypes.h:176
PlaybackBox::m_playList
QList< uint > m_playList
list of selected items "play list"
Definition: playbackbox.h:435
MythConfirmationDialog
Dialog asking for user confirmation. Ok and optional Cancel button.
Definition: mythdialogbox.h:272
ProgramInfo::ToStringList
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
Definition: programinfo.cpp:1276
PlaybackBox::GetCurrentProgram
ProgramInfo * GetCurrentProgram(void) const override
Definition: playbackbox.cpp:2294
ProgramInfo::GetSeason
uint GetSeason(void) const
Definition: programinfo.h:367
mythcorecontext.h
wlExpireOff
@ wlExpireOff
Definition: programtypes.h:189
PlaybackBox::m_passwordEntered
bool m_passwordEntered
Definition: playbackbox.h:465
mythuitextedit.h
MythUICheckBox::SetCheckState
void SetCheckState(MythUIStateType::StateType state)
Definition: mythuicheckbox.cpp:66
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:701
JobQueue::IsJobStatusRunning
static bool IsJobStatusRunning(int status)
Definition: jobqueue.cpp:1079
MythUIButtonListItem::SetImage
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
Definition: mythuibuttonlist.cpp:3479
PlaybackBox::customEvent
void customEvent(QEvent *event) override
Definition: playbackbox.cpp:3932
PlaybackBox::doAllowRerecord
void doAllowRerecord()
Callback function when Allow Re-record is pressed in Watch Recordings.
Definition: playbackbox.cpp:3325
PlaybackBox::PlaylistDeleteForgetHistory
void PlaylistDeleteForgetHistory(void)
Definition: playbackbox.h:259
PlaybackBox::m_allOrder
int m_allOrder
allOrder controls the ordering of the "All Programs" list
Definition: playbackbox.h:391
JOB_STOP
@ JOB_STOP
Definition: jobqueue.h:54
MetadataLookup::GetInetref
QString GetInetref() const
Definition: metadatacommon.h:356
ProgramInfo::GetCategoryTypeString
QString GetCategoryTypeString(void) const
Returns catType as a string.
Definition: programinfo.cpp:1898
PlaybackBox::doBeginUserJob3
void doBeginUserJob3()
Definition: playbackbox.h:241
PlaybackBox::extract_job_state
QString extract_job_state(const ProgramInfo &pginfo)
Definition: playbackbox.cpp:292
PlaybackBox::ClearLastPlayPos
void ClearLastPlayPos()
Definition: playbackbox.cpp:2231
iconMap
static QMap< QString, QString > iconMap
Definition: musicutils.cpp:33
ProgramInfo::GetPlaybackURL
QString GetPlaybackURL(bool checkMaster=false, bool forceCheckLocal=false)
Returns filename or URL to be used to play back this recording.
Definition: programinfo.cpp:2557
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
PlaybackBox::PlayFromAnyMark
void PlayFromAnyMark()
Definition: playbackbox.h:150
PlaybackBox::ViewMask
ViewMask
Definition: playbackbox.h:87
DialogCompletionEvent
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
PlaybackBox::doPlaylistWatchedSetOff
void doPlaylistWatchedSetOff()
Definition: playbackbox.h:267
GroupSelector::m_label
QString m_label
Definition: playbackbox.h:515
PlaybackBox::ShowRecGroupChangerNoPlaylist
void ShowRecGroupChangerNoPlaylist(void)
Definition: playbackbox.h:180
PlaybackBox::UpdateUsageUI
void UpdateUsageUI(void)
Definition: playbackbox.cpp:1318
comp_recpriority2_less_than
static bool comp_recpriority2_less_than(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:177
ProgramInfoCache::UpdateFileSize
void UpdateFileSize(uint recordingID, uint64_t filesize, UpdateStates flags)
Updates a ProgramInfo in the cache.
Definition: programinfocache.cpp:236
JOB_USERJOB2
@ JOB_USERJOB2
Definition: jobqueue.h:85
PlaybackBox::kMySlots
static std::array< PlaybackBoxCb, kMaxJobs *2 > kMySlots
Definition: playbackbox.h:122
PlaybackBox::m_artHostOverride
QString m_artHostOverride
Definition: playbackbox.h:368
PlaybackBox::toggleWatched
void toggleWatched()
Definition: playbackbox.cpp:3582
PlaybackBox::processNetworkControlCommand
void processNetworkControlCommand(const QString &command)
Definition: playbackbox.cpp:3729
PlaybackBox::HandleUpdateItemEvent
void HandleUpdateItemEvent(uint recordingId, uint flags)
Definition: playbackbox.cpp:4368
PlaybackBox::togglePlayListTitle
void togglePlayListTitle(void)
Definition: playbackbox.cpp:3651
ProgramInfo::SaveWatched
void SaveWatched(bool watchedFlag)
Set "watched" field in recorded/videometadata to "watchedFlag".
Definition: programinfo.cpp:3062
PlaybackBox::m_recGroup
QString m_recGroup
Definition: playbackbox.h:397
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
PlaybackBox::ShowGroupPopup
void ShowGroupPopup(void)
Definition: playbackbox.cpp:2363
RecordingInfo::ApplyTranscoderProfileChangeById
void ApplyTranscoderProfileChangeById(int id)
Definition: recordinginfo.cpp:828
MythUIType::SetVisible
virtual void SetVisible(bool visible)
Definition: mythuitype.cpp:1105
PlaybackBox::m_delList
QStringList m_delList
Recording[s] currently selected for deletion.
Definition: playbackbox.h:430
PlaybackBox::m_progLists
ProgramMap m_progLists
lists of programs by page
Definition: playbackbox.h:420
TVState
TVState
TVState is an enumeration of the states used by TV and TVRec.
Definition: tv.h:53
ProgramInfo::IsAutoExpirable
bool IsAutoExpirable(void) const
Definition: programinfo.h:487
PasswordChange::result
void result(const QString &)
ScheduleCommon::ShowUpcoming
virtual void ShowUpcoming(void) const
Show the upcoming recordings for this title.
Definition: schedulecommon.cpp:69
PlaybackBox::VIEW_RECGROUPS
@ VIEW_RECGROUPS
Definition: playbackbox.h:91
PasswordChange::m_okButton
MythUIButton * m_okButton
Definition: playbackbox.h:565
DialogCompletionEvent::kEventType
static const Type kEventType
Definition: mythdialogbox.h:57
PlaybackBox::m_noRecordingsText
MythUIText * m_noRecordingsText
Definition: playbackbox.h:361
PlaybackBox::doBeginFlagging
void doBeginFlagging()
Definition: playbackbox.cpp:3389
MythUIButtonList::Reset
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuibuttonlist.cpp:116
PlaybackBox::FindProgramInUILists
ProgramInfo * FindProgramInUILists(const ProgramInfo &pginfo)
Definition: playbackbox.cpp:3545
HelpPopup::addItem
void addItem(const QString &state, const QString &text)
Definition: playbackbox.cpp:5487
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
ProgramInfoCache::PIC_NO_ACTION
@ PIC_NO_ACTION
Definition: programinfocache.h:29
RecMetadataEdit::m_subtitleEdit
MythUITextEdit * m_subtitleEdit
Definition: playbackbox.h:594
PlaybackBox::m_recgroupList
MythUIButtonList * m_recgroupList
Definition: playbackbox.h:357
ProgramInfoCache::Remove
bool Remove(uint recordingID)
Marks a ProgramInfo in the cache for deletion on the next call to Refresh().
Definition: programinfocache.cpp:287
ProgramInfo::SetFlagging
void SetFlagging(bool flagging)
Definition: programinfo.h:555
MythUIButtonList::SetItemCurrent
void SetItemCurrent(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1581
JOB_TRANSCODE
@ JOB_TRANSCODE
Definition: jobqueue.h:78
ACTION_PAGELEFT
#define ACTION_PAGELEFT
Definition: tv_actions.h:11
build_compdb.action
action
Definition: build_compdb.py:9
RecMetadataEdit::customEvent
void customEvent(QEvent *event) override
Definition: playbackbox.cpp:5368
MythUISpinBox
A widget for offering a range of numerical values where only the the bounding values and interval are...
Definition: mythuispinbox.h:16
PlaybackBox::SelectNextRecGroup
void SelectNextRecGroup(void)
Definition: playbackbox.cpp:1462
previewgeneratorqueue.h
PlaybackBox::doPlaylistBeginUserJob4
void doPlaylistBeginUserJob4()
Definition: playbackbox.h:256
PlaybackBox::kDeleteRecording
@ kDeleteRecording
Definition: playbackbox.h:101
PlaybackBox::displayRecGroup
void displayRecGroup(const QString &newRecGroup="")
Definition: playbackbox.cpp:602
PlaybackBox::createStorageMenu
MythMenu * createStorageMenu()
Definition: playbackbox.cpp:2942
AvailableStatusType
AvailableStatusType
Definition: programtypes.h:175
GroupSelector::m_list
QStringList m_list
Definition: playbackbox.h:516
comp_programid_rev_less_than
static bool comp_programid_rev_less_than(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:159
PlaybackBox::Undelete
void Undelete(void)
Definition: playbackbox.cpp:3487
MythScreenType::Exiting
void Exiting()
extract_subtitle
static QString extract_subtitle(const ProgramInfo &pginfo, const QString &groupname)
Definition: playbackbox.cpp:326
PlaybackBox::m_watchedProgress
MythUIProgressBar * m_watchedProgress
Definition: playbackbox.h:366
mythuibutton.h
kProbableTelevision
@ kProbableTelevision
Definition: metadatacommon.h:51
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:322
PlaybackBox::ShowPlayGroupChangerNoPlaylist
void ShowPlayGroupChangerNoPlaylist(void)
Definition: playbackbox.h:182
JobQueue::IsJobStatusQueued
static bool IsJobStatusQueued(int status)
Definition: jobqueue.cpp:1074
PlaybackBoxHelper::StopRecording
void StopRecording(const ProgramInfo &pginfo)
Definition: playbackboxhelper.cpp:369
MythUITextEdit::valueChanged
void valueChanged()
PlaybackBox::stopPlaylistUserJob1
void stopPlaylistUserJob1()
Definition: playbackbox.h:251
PlaybackBox::m_watchListAutoExpire
bool m_watchListAutoExpire
exclude recording not marked for auto-expire from the Watch List
Definition: playbackbox.h:385
PlaybackBox::VIEW_TITLES
@ VIEW_TITLES
Definition: playbackbox.h:89
PlaybackBox::createRecordingMenu
MythMenu * createRecordingMenu()
Definition: playbackbox.cpp:2963
PlaybackBox::m_programInfoCache
ProgramInfoCache m_programInfoCache
Definition: playbackbox.h:439
PlaybackBox::Play
bool Play(const ProgramInfo &rec, bool inPlaylist, bool ignoreBookmark, bool ignoreProgStart, bool ignoreLastPlayPos, bool underNetworkControl)
Definition: playbackbox.cpp:2404
mythuiactions.h
LOC
#define LOC
Definition: playbackbox.cpp:56
mconcurrent.h
PlaybackBox::m_groupDisplayName
QString m_groupDisplayName
Definition: playbackbox.h:396
ProgramInfo::GetProgramID
QString GetProgramID(void) const
Definition: programinfo.h:440
azlyrics.info
dictionary info
Definition: azlyrics.py:7
ProgramInfo::QueryIsInUse
bool QueryIsInUse(QStringList &byWho) const
Returns true if Program is in use.
Definition: programinfo.cpp:3193
RecMetadataEdit::Create
bool Create(void) override
Definition: playbackbox.cpp:5216
MythUIStateType::Full
@ Full
Definition: mythuistatetype.h:27
PlaybackBox::createJobMenu
MythMenu * createJobMenu()
Definition: playbackbox.cpp:3008
restore_position
static void restore_position(MythUIButtonList *groupList, MythUIButtonList *recordingList, const QStringList &groupSelPref, const QStringList &itemSelPref, const QStringList &itemTopPref)
Definition: playbackbox.cpp:1587
RecordingInfo::ApplyRecordRecTitleChange
void ApplyRecordRecTitleChange(const QString &newTitle, const QString &newSubtitle, const QString &newDescription)
Sets the recording title, subtitle, and description both in this RecordingInfo and in the database.
Definition: recordinginfo.cpp:796
MythUIButtonListItem::GetImageFilename
QString GetImageFilename(const QString &name="") const
Definition: mythuibuttonlist.cpp:3573
RecMetadataEdit::ClearInetref
void ClearInetref()
Definition: playbackbox.cpp:5268
PlaybackBox::m_watchListBlackOut
std::chrono::hours m_watchListBlackOut
adjust exclusion of a title from the Watch List after a delete
Definition: playbackbox.h:389
MythDate::kDateTimeFull
@ kDateTimeFull
Default local time.
Definition: mythdate.h:23
comp_season_rev_less_than
static bool comp_season_rev_less_than(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:201
asDeleted
@ asDeleted
Definition: programtypes.h:181
ProgramInfo::GetRecordingPriority2
int GetRecordingPriority2(void) const
Definition: programinfo.h:445
PlaybackBoxHelper::LocateArtwork
QString LocateArtwork(const QString &inetref, uint season, VideoArtworkType type, const ProgramInfo *pginfo, const QString &groupname=nullptr)
Definition: playbackboxhelper.cpp:452
MythTextInputDialog
Dialog prompting the user to enter a text string.
Definition: mythdialogbox.h:314
PlaybackBox::m_recGroupType
QMap< QString, QString > m_recGroupType
Definition: playbackbox.h:414
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:885
RecMetadataEdit::QueryComplete
void QueryComplete(MetadataLookup *lookup)
Definition: playbackbox.cpp:5345
MythDate::kTime
@ kTime
Default local time.
Definition: mythdate.h:22
PlaybackBox::toggleLiveTVView
void toggleLiveTVView(bool setOn)
Definition: playbackbox.h:219
mythuicheckbox.h
kArtworkBannerTimeout
static constexpr uint8_t kArtworkBannerTimeout
Definition: playbackbox.h:58
MythUIImage::SetFilename
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
Definition: mythuiimage.cpp:677
RecordingInfo::ApplyRecordRecGroupChange
void ApplyRecordRecGroupChange(const QString &newrecgroup)
Sets the recording group, both in this RecordingInfo and in the database.
Definition: recordinginfo.cpp:659
comp_programid_less_than
static bool comp_programid_less_than(const ProgramInfo *a, const ProgramInfo *b)
Definition: playbackbox.cpp:153
PlaybackBox::m_alwaysShowWatchedProgress
bool m_alwaysShowWatchedProgress
Definition: playbackbox.h:467
PlaybackBox::togglePlayListItem
void togglePlayListItem(void)
Definition: playbackbox.cpp:3662
PlaybackBox::m_opOnPlaylist
bool m_opOnPlaylist
Definition: playbackbox.h:436
recordingrule.h
MythUIButtonList
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
Definition: mythuibuttonlist.h:191
PlaybackBox::m_recordingList
MythUIButtonList * m_recordingList
Definition: playbackbox.h:359
PlaybackBoxHelper::GetFreeSpaceUsedMB
uint64_t GetFreeSpaceUsedMB(void) const
Definition: playbackboxhelper.cpp:424
ReferenceCounter::IncrRef
virtual int IncrRef(void)
Increments reference count.
Definition: referencecounter.cpp:101
ProgramInfo::GetSubtitleType
uint GetSubtitleType(void) const
Definition: programinfo.h:497
kStartTVNoFlags
@ kStartTVNoFlags
Definition: tv_play.h:113
asFileNotFound
@ asFileNotFound
Definition: programtypes.h:179
ProgramInfo::GetAvailableStatus
AvailableStatusType GetAvailableStatus(void) const
Definition: programinfo.h:846
mythmainwindow.h
PlaybackBox::ShowRecordedEpisodes
void ShowRecordedEpisodes()
Definition: playbackbox.cpp:3516
mythnotificationcenter.h
PlaybackBox::DeleteIgnore
void DeleteIgnore(void)
Definition: playbackbox.h:200
PlaybackBox::fanartLoad
void fanartLoad(void)
Definition: playbackbox.cpp:2495
PlaybackBox::askStop
void askStop()
Definition: playbackbox.cpp:3309
PlaybackBox::PlaylistDeleteKeepHistory
void PlaylistDeleteKeepHistory(void)
Definition: playbackbox.h:260
GroupSelector
Definition: playbackbox.h:492
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
PlaybackBox::doBeginLookup
void doBeginLookup()
Definition: playbackbox.cpp:3394
PlaybackBox::doPlaylistJobQueueJob
void doPlaylistJobQueueJob(int jobType, int jobFlags=0)
Definition: playbackbox.cpp:3399
MythCoreContext::dispatch
void dispatch(const MythEvent &event)
Definition: mythcorecontext.cpp:1727
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:566
ProgramInfo::IsBookmarkSet
bool IsBookmarkSet(void) const
Definition: programinfo.h:484
PlaybackBox::m_networkControlCommands
std::deque< QString > m_networkControlCommands
Definition: playbackbox.h:452
MythRandomStd::MythRandom
uint32_t MythRandom()
generate 32 random bits
Definition: mythrandom.h:20
PlaybackBox::doPlaylistExpireSetOn
void doPlaylistExpireSetOn()
Definition: playbackbox.h:263
PlaybackBox::ShowAvailabilityPopup
static void ShowAvailabilityPopup(const ProgramInfo &pginfo)
Definition: playbackbox.cpp:2607
PlaybackBox::m_watchListStart
bool m_watchListStart
use the Watch List as the initial view
Definition: playbackbox.h:383
s_artDelay
static const std::array< const uint, 3 > s_artDelay
Definition: playbackbox.cpp:208
PlaybackBoxHelper::CheckAvailability
void CheckAvailability(const ProgramInfo &pginfo, CheckAvailabilityType cat=kCheckForCache)
Definition: playbackboxhelper.cpp:430
MythObservable::removeListener
void removeListener(QObject *listener)
Remove a listener to the observable.
Definition: mythobservable.cpp:55
PlaybackBox::ShowRecGroupChanger
void ShowRecGroupChanger(bool use_playlist=false)
Used to change the recording group of a program or playlist.
Definition: playbackbox.cpp:4635
kArtworkFanTimeout
static constexpr uint16_t kArtworkFanTimeout
Definition: playbackbox.h:57
PlaybackBoxHelper::ForceFreeSpaceUpdate
void ForceFreeSpaceUpdate(void)
Definition: playbackboxhelper.cpp:363
GroupSelector::m_data
QStringList m_data
Definition: playbackbox.h:517
MythUIStateType
This widget is used for grouping other widgets for display when a particular named state is called....
Definition: mythuistatetype.h:22
MythCoreContext::SaveBoolSetting
void SaveBoolSetting(const QString &key, bool newValue)
Definition: mythcorecontext.h:160
disp_flags
static const std::array< const std::string, 9 > disp_flags
Definition: playbackbox.cpp:773
PlaybackBox::PlaybackBoxListItem
friend class PlaybackBoxListItem
Definition: playbackbox.h:64
PlaybackBox::SwitchList
void SwitchList(void)
Definition: playbackbox.cpp:594
ProgramInfo::HasPathname
bool HasPathname(void) const
Definition: programinfo.h:359
find
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
Definition: dvbstreamhandler.cpp:363
PlaybackBox::HandleRecordingRemoveEvent
void HandleRecordingRemoveEvent(uint recordingID)
Definition: playbackbox.cpp:4285
MythUIStateType::DisplayState
bool DisplayState(const QString &name)
Definition: mythuistatetype.cpp:84
PlaybackBox::ShowPlayGroupChangerUsePlaylist
void ShowPlayGroupChangerUsePlaylist(void)
Definition: playbackbox.h:181
ProgramInfo::SaveLastPlayPos
void SaveLastPlayPos(uint64_t frame)
TODO Move to RecordingInfo.
Definition: programinfo.cpp:2717
wlWatched
@ wlWatched
Definition: programtypes.h:188
MythUIButtonListItem::SetProgress1
void SetProgress1(int start, int total, int used)
Definition: mythuibuttonlist.cpp:3593
uint
unsigned int uint
Definition: freesurround.h:24
GroupSelector::Create
bool Create(void) override
Definition: playbackbox.cpp:5018
kCheckForCache
@ kCheckForCache
Definition: playbackboxhelper.h:23
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:902
PlaybackBox::m_usingGroupSelector
bool m_usingGroupSelector
Definition: playbackbox.h:463
kStartTVByNetworkCommand
@ kStartTVByNetworkCommand
Definition: tv_play.h:115
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
HelpPopup::m_iconList
MythUIButtonList * m_iconList
Definition: playbackbox.h:620
PlaybackBox::ShowPlayGroupChanger
void ShowPlayGroupChanger(bool use_playlist=false)
Used to change the play group of a program or playlist.
Definition: playbackbox.cpp:4700
ProgramInfo::GetSubtitle
QString GetSubtitle(void) const
Definition: programinfo.h:364
PlaybackBox::toggleView
void toggleView(PlaybackBox::ViewMask itemMask, bool setOn)
Definition: playbackbox.cpp:3641
RecMetadataEdit::m_progInfo
ProgramInfo * m_progInfo
Definition: playbackbox.h:602
TV
Control TV playback.
Definition: tv_play.h:154