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