MythTV  master
recordingselector.cpp
Go to the documentation of this file.
1 
2 // c++
3 #include <cstdlib>
4 #include <unistd.h>
5 
6 // qt
7 #include <QApplication>
8 #include <QDir>
9 #include <QKeyEvent>
10 #include <QTimer>
11 
12 // mythtv
13 #include <libmyth/mythcontext.h>
14 #include <libmythbase/mthread.h>
15 #include <libmythbase/mythdate.h>
16 #include <libmythbase/mythdb.h>
18 #include <libmythbase/mythtimer.h>
20 #include <libmythbase/remoteutil.h>
21 #include <libmythbase/stringutil.h>
25 #include <libmythui/mythuibutton.h>
27 #include <libmythui/mythuiimage.h>
28 #include <libmythui/mythuitext.h>
29 
30 // mytharchive
31 #include "archiveutil.h"
32 #include "recordingselector.h"
33 
35 {
36  public:
38  MThread("GetRecordingList"), m_parent(parent)
39  {
40  start();
41  }
42 
43  void run(void) override // MThread
44  {
45  RunProlog();
47  RunEpilog();
48  }
49 
51 };
52 
54 {
55  delete m_recordingList;
56  while (!m_selectedList.isEmpty())
57  delete m_selectedList.takeFirst();
58 }
59 
61 {
62  // Load the theme for this screen
63  bool foundtheme = LoadWindowFromXML("mytharchive-ui.xml", "recording_selector", this);
64  if (!foundtheme)
65  return false;
66 
67  bool err = false;
68  UIUtilE::Assign(this, m_okButton, "ok_button", &err);
69  UIUtilE::Assign(this, m_cancelButton, "cancel_button", &err);
70  UIUtilE::Assign(this, m_categorySelector, "category_selector", &err);
71  UIUtilE::Assign(this, m_recordingButtonList, "recordinglist", &err);
72 
73  UIUtilW::Assign(this, m_titleText, "progtitle", &err);
74  UIUtilW::Assign(this, m_datetimeText, "progdatetime", &err);
75  UIUtilW::Assign(this, m_descriptionText, "progdescription", &err);
76  UIUtilW::Assign(this, m_filesizeText, "filesize", &err);
77  UIUtilW::Assign(this, m_previewImage, "preview_image", &err);
78  UIUtilW::Assign(this, m_cutlistImage, "cutlist_image", &err);
79 
80  if (err)
81  {
82  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'recording_selector'");
83  return false;
84  }
85 
88 
89  new MythUIButtonListItem(m_categorySelector, tr("All Recordings"));
92 
97 
98  if (m_cutlistImage)
100 
101  BuildFocusList();
102 
104 
105  return true;
106 }
107 
109 {
110  QString message = tr("Retrieving Recording List.\nPlease Wait...");
111 
112  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
113 
114  auto *busyPopup = new
115  MythUIBusyDialog(message, popupStack, "recordingselectorbusydialog");
116 
117  if (busyPopup->Create())
118  popupStack->AddScreen(busyPopup, false);
119  else
120  {
121  delete busyPopup;
122  busyPopup = nullptr;
123  }
124 
125  auto *thread = new GetRecordingListThread(this);
126  while (thread->isRunning())
127  {
128  QCoreApplication::processEvents();
129  usleep(2000);
130  }
131 
132  if (!m_recordingList || m_recordingList->empty())
133  {
134  ShowOkPopup(tr("Either you don't have any recordings or "
135  "no recordings are available locally!"));
136  if (busyPopup)
137  busyPopup->Close();
138 
139  Close();
140  return;
141  }
142 
146 
147  if (busyPopup)
148  busyPopup->Close();
149 }
150 
151 bool RecordingSelector::keyPressEvent(QKeyEvent *event)
152 {
153  if (GetFocusWidget()->keyPressEvent(event))
154  return true;
155 
156  QStringList actions;
157  bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
158 
159  for (int i = 0; i < actions.size() && !handled; i++)
160  {
161  QString action = actions[i];
162  handled = true;
163 
164  if (action == "MENU")
165  {
166  ShowMenu();
167  }
168  else
169  handled = false;
170  }
171 
172  if (!handled && MythScreenType::keyPressEvent(event))
173  handled = true;
174 
175  return handled;
176 }
177 
179 {
180  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
181 
182  auto *menuPopup = new MythDialogBox(tr("Menu"), popupStack, "actionmenu");
183 
184  if (menuPopup->Create())
185  popupStack->AddScreen(menuPopup);
186 
187  menuPopup->SetReturnEvent(this, "action");
188 
189  menuPopup->AddButton(tr("Clear All"), &RecordingSelector::clearAll);
190  menuPopup->AddButton(tr("Select All"), &RecordingSelector::selectAll);
191 }
192 
194 {
195  while (!m_selectedList.isEmpty())
196  m_selectedList.takeFirst();
197  m_selectedList.clear();
198 
199  for (auto *p : *m_recordingList)
200  m_selectedList.append(p);
201 
203 }
204 
206 {
207  while (!m_selectedList.isEmpty())
208  m_selectedList.takeFirst();
209  m_selectedList.clear();
210 
212 }
213 
215 {
217  {
218  int index = m_selectedList.indexOf(item->GetData().value<ProgramInfo *>());
219  if (index != -1)
220  m_selectedList.takeAt(index);
222  }
223  else
224  {
225  int index = m_selectedList.indexOf(item->GetData().value<ProgramInfo *>());
226  if (index == -1)
227  m_selectedList.append(item->GetData().value<ProgramInfo *>());
228 
230  }
231 }
232 
234 {
235  auto *p = item->GetData().value<ProgramInfo *>();
236 
237  if (!p)
238  return;
239 
240  if (m_titleText)
241  m_titleText->SetText(p->GetTitle());
242 
243  if (m_datetimeText)
244  m_datetimeText->SetText(p->GetScheduledStartTime().toLocalTime()
245  .toString("dd MMM yy (hh:mm)"));
246 
247  if (m_descriptionText)
248  {
250  ((!p->GetSubtitle().isEmpty()) ? p->GetSubtitle() + "\n" : "") +
251  p->GetDescription());
252  }
253 
254  if (m_filesizeText)
255  {
256  m_filesizeText->SetText(StringUtil::formatKBytes(p->GetFilesize() / 1024));
257  }
258 
259  if (m_cutlistImage)
260  {
261  if (p->HasCutlist())
262  m_cutlistImage->Show();
263  else
264  m_cutlistImage->Hide();
265  }
266 
267  if (m_previewImage)
268  {
269  // try to locate a preview image
270  if (QFile::exists(p->GetPathname() + ".png"))
271  {
272  m_previewImage->SetFilename(p->GetPathname() + ".png");
273  m_previewImage->Load();
274  }
275  else
276  {
277  m_previewImage->SetFilename("blank.png");
278  m_previewImage->Load();
279  }
280  }
281 }
282 
284 {
285  // loop though selected recordings and add them to the list
286  // remove any items that have been removed from the list
287  QList<ArchiveItem *> tempAList;
288  for (auto *a : std::as_const(*m_archiveList))
289  {
290  bool found = false;
291 
292  for (auto *p : std::as_const(m_selectedList))
293  {
294  if (a->type != "Recording" || a->filename == p->GetPlaybackURL(false, true))
295  {
296  found = true;
297  break;
298  }
299  }
300 
301  if (!found)
302  tempAList.append(a);
303  }
304 
305  for (auto *x : std::as_const(tempAList))
306  m_archiveList->removeAll(x);
307 
308  // remove any items that are already in the list
309  QList<ProgramInfo *> tempSList;
310  for (auto *p : std::as_const(m_selectedList))
311  {
312  for (const auto *a : std::as_const(*m_archiveList))
313  {
314  if (a->filename == p->GetPlaybackURL(false, true))
315  {
316  tempSList.append(p);
317  break;
318  }
319  }
320  }
321 
322  for (auto *x : std::as_const(tempSList))
323  m_selectedList.removeAll(x);
324 
325  // add all that are left
326  for (auto *p : std::as_const(m_selectedList))
327  {
328  auto *a = new ArchiveItem;
329  a->type = "Recording";
330  a->title = p->GetTitle();
331  a->subtitle = p->GetSubtitle();
332  a->description = p->GetDescription();
333  a->startDate = p->GetScheduledStartTime()
334  .toLocalTime().toString("dd MMM yy");
335  a->startTime = p->GetScheduledStartTime()
336  .toLocalTime().toString("(hh:mm)");
337  a->size = p->GetFilesize();
338  a->filename = p->GetPlaybackURL(false, true);
339  a->hasCutlist = p->HasCutlist();
340  a->useCutlist = false;
341  a->duration = 0;
342  a->cutDuration = 0;
343  a->videoWidth = 0;
344  a->videoHeight = 0;
345  a->fileCodec = "";
346  a->videoCodec = "";
347  a->encoderProfile = nullptr;
348  a->editedDetails = false;
349  m_archiveList->append(a);
350  }
351 
352  emit haveResult(true);
353  Close();
354 }
355 
357 {
358  emit haveResult(false);
359  Close();
360 }
361 
363 {
364  if (!m_recordingList || m_recordingList->empty())
365  return;
366 
368 
369  if (m_categorySelector)
370  {
371  for (auto *p : *m_recordingList)
372  {
373  if (p->GetTitle() == m_categorySelector->GetValue() ||
374  m_categorySelector->GetValue() == tr("All Recordings"))
375  {
376  auto* item = new MythUIButtonListItem(
378  p->GetTitle() + " ~ " +
379  p->GetScheduledStartTime().toLocalTime()
380  .toString("dd MMM yy (hh:mm)"));
381  item->setCheckable(true);
382  if (m_selectedList.indexOf(p) != -1)
383  {
384  item->setChecked(MythUIButtonListItem::FullChecked);
385  }
386  else
387  {
388  item->setChecked(MythUIButtonListItem::NotChecked);
389  }
390 
391  QString title = p->GetTitle();
392  QString subtitle = p->GetSubtitle();
393 
394  QDateTime recstartts = p->GetScheduledStartTime();
395  QDateTime recendts = p->GetScheduledEndTime();
396 
397  QString timedate = QString("%1 - %2")
400 
401  uint season = p->GetSeason();
402  uint episode = p->GetEpisode();
403  QString seasone;
404  QString seasonx;
405 
406  if (season && episode)
407  {
408  seasone = QString("s%1e%2")
409  .arg(StringUtil::intToPaddedString(season, 2),
410  StringUtil::intToPaddedString(episode, 2));
411  seasonx = QString("%1x%2")
412  .arg(StringUtil::intToPaddedString(season, 1),
413  StringUtil::intToPaddedString(episode, 2));
414  }
415 
416  item->SetText(title, "title");
417  item->SetText(subtitle, "subtitle");
418  if (subtitle.isEmpty())
419  item->SetText(title, "titlesubtitle");
420  else
421  item->SetText(title + " - \"" + subtitle + '"',
422  "titlesubtitle");
423 
424  item->SetText(timedate, "timedate");
425  item->SetText(p->GetDescription(), "description");
426  item->SetText(StringUtil::formatKBytes(p->GetFilesize() / 1024),
427  "filesize_str");
428 
429  item->SetText(QString::number(season), "season");
430  item->SetText(QString::number(episode), "episode");
431  item->SetText(seasonx, "00x00");
432  item->SetText(seasone, "s00e00");
433 
434  item->DisplayState(p->HasCutlist() ? "yes" : "no", "cutlist");
435 
436  item->SetData(QVariant::fromValue(p));
437  }
438  QCoreApplication::processEvents();
439  }
440  }
441 
444 }
445 
447 {
449  m_categories.clear();
450 
451  if (m_recordingList && !m_recordingList->empty())
452  {
453  auto i = m_recordingList->begin();
454  for ( ; i != m_recordingList->end(); ++i)
455  {
456  ProgramInfo *p = *i;
457  // ignore live tv and deleted recordings
458  if (p->GetRecordingGroup() == "LiveTV" ||
459  p->GetRecordingGroup() == "Deleted")
460  {
461  i = m_recordingList->erase(i);
462  --i;
463  continue;
464  }
465 
466  if (m_categories.indexOf(p->GetTitle()) == -1)
467  m_categories.append(p->GetTitle());
468  }
469  }
470 }
471 
473 {
474  // sort and add categories to selector
475  m_categories.sort();
476 
477  if (m_categorySelector)
478  {
479  new MythUIButtonListItem(m_categorySelector, tr("All Recordings"));
481 
482  for (int x = 0; x < m_categories.count(); x++)
483  {
485  }
486  }
487 }
488 
490 {
492 }
493 
495 {
496  if (!m_recordingList)
497  return;
498 
499  m_selectedList.clear();
500 
501  for (const auto *a : std::as_const(*m_archiveList))
502  {
503  for (auto *p : *m_recordingList)
504  {
505  if (p->GetPlaybackURL(false, true) == a->filename)
506  {
507  if (m_selectedList.indexOf(p) == -1)
508  m_selectedList.append(p);
509  break;
510  }
511 
512  QCoreApplication::processEvents();
513  }
514  }
515 }
MythUIButton::Clicked
void Clicked()
RecordingSelector::haveResult
void haveResult(bool ok)
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1591
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
mythuitext.h
GetRecordingListThread
Definition: recordingselector.cpp:34
mythdb.h
RecordingSelector::Create
bool Create() override
Definition: recordingselector.cpp:60
GetRecordingListThread::m_parent
RecordingSelector * m_parent
Definition: recordingselector.cpp:50
RecordingSelector::setCategory
void setCategory(MythUIButtonListItem *item)
Definition: recordingselector.cpp:489
MythScreenType::Close
virtual void Close()
Definition: mythscreentype.cpp:386
MythUIImage::Load
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
Definition: mythuiimage.cpp:966
GetRecordingListThread::run
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: recordingselector.cpp:43
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
RecordingSelector::ShowMenu
void ShowMenu(void) override
Definition: recordingselector.cpp:178
RecordingSelector::m_categorySelector
MythUIButtonList * m_categorySelector
Definition: recordingselector.h:73
mythdialogbox.h
MythScreenStack
Definition: mythscreenstack.h:16
MythUIButtonListItem::FullChecked
@ FullChecked
Definition: mythuibuttonlist.h:48
RecordingSelector::toggleSelected
void toggleSelected(MythUIButtonListItem *item)
Definition: recordingselector.cpp:214
RecordingSelector::keyPressEvent
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
Definition: recordingselector.cpp:151
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
RecordingSelector::m_filesizeText
MythUIText * m_filesizeText
Definition: recordingselector.h:76
remoteutil.h
mythuibuttonlist.h
mythuiimage.h
mythprogressdialog.h
RecordingSelector::m_titleText
MythUIText * m_titleText
Definition: recordingselector.h:74
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:113
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
recordingselector.h
RecordingSelector::getRecordingList
void getRecordingList(void)
Definition: recordingselector.cpp:446
RecordingSelector::selectAll
void selectAll(void)
Definition: recordingselector.cpp:193
ArchiveItem::type
QString type
Definition: archiveutil.h:53
RecordingSelector::clearAll
void clearAll(void)
Definition: recordingselector.cpp:205
RecordingSelector::m_previewImage
MythUIImage * m_previewImage
Definition: recordingselector.h:78
mythdate.h
RecordingSelector
Definition: recordingselector.h:29
programinfo.h
MythUIType::Show
void Show(void)
Definition: mythuitype.cpp:1149
mythlogging.h
MythUIButtonList::itemClicked
void itemClicked(MythUIButtonListItem *item)
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
hardwareprofile.config.p
p
Definition: config.py:33
RecordingSelector::Init
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
Definition: recordingselector.cpp:108
archiveutil.h
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:118
RecordingSelector::titleChanged
void titleChanged(MythUIButtonListItem *item)
Definition: recordingselector.cpp:233
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:166
RecordingSelector::m_selectedList
QList< ProgramInfo * > m_selectedList
Definition: recordingselector.h:67
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:206
stringutil.h
RecordingSelector::updateRecordingList
void updateRecordingList(void)
Definition: recordingselector.cpp:362
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
RecordingSelector::updateSelectedList
void updateSelectedList(void)
Definition: recordingselector.cpp:494
MythUIBusyDialog
Definition: mythprogressdialog.h:36
StringUtil::intToPaddedString
QString intToPaddedString(int n, int width=2)
Creates a zero padded string representation of an integer.
Definition: stringutil.h:24
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3660
uint
unsigned int uint
Definition: compat.h:81
UIUtilDisp::Assign
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
RecordingSelector::cancelPressed
void cancelPressed(void)
Definition: recordingselector.cpp:356
MythUIType::Hide
void Hide(void)
Definition: mythuitype.cpp:1144
RecordingSelector::updateCategorySelector
void updateCategorySelector(void)
Definition: recordingselector.cpp:472
StringUtil::formatKBytes
MBASE_PUBLIC QString formatKBytes(int64_t sizeKB, int prec=1)
Definition: stringutil.cpp:357
RecordingSelector::m_okButton
MythUIButton * m_okButton
Definition: recordingselector.h:71
RecordingSelector::m_recordingButtonList
MythUIButtonList * m_recordingButtonList
Definition: recordingselector.h:70
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
MythScreenType::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythscreentype.cpp:404
RecordingSelector::m_datetimeText
MythUIText * m_datetimeText
Definition: recordingselector.h:75
RecordingSelector::GetRecordingListThread
friend class GetRecordingListThread
Definition: recordingselector.h:81
RecordingSelector::m_recordingList
std::vector< ProgramInfo * > * m_recordingList
Definition: recordingselector.h:66
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:687
MythUIButtonList::GetValue
virtual QString GetValue() const
Definition: mythuibuttonlist.cpp:1610
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:132
MythUIButtonListItem::state
CheckState state() const
Definition: mythuibuttonlist.cpp:3614
RecordingSelector::~RecordingSelector
~RecordingSelector(void) override
Definition: recordingselector.cpp:53
mythcontext.h
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
mthread.h
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
RecordingSelector::m_cutlistImage
MythUIImage * m_cutlistImage
Definition: recordingselector.h:79
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
MythUIButtonList::SetItemCurrent
void SetItemCurrent(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1558
build_compdb.action
action
Definition: build_compdb.py:9
RecordingSelector::m_categories
QStringList m_categories
Definition: recordingselector.h:68
mythuibutton.h
mythtimer.h
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:323
RecordingSelector::m_descriptionText
MythUIText * m_descriptionText
Definition: recordingselector.h:77
GetRecordingListThread::GetRecordingListThread
GetRecordingListThread(RecordingSelector *parent)
Definition: recordingselector.cpp:37
MythDate::kDateTimeFull
@ kDateTimeFull
Default local time.
Definition: mythdate.h:23
ArchiveItem
Definition: archiveutil.h:50
RemoteGetRecordedList
std::vector< ProgramInfo * > * RemoteGetRecordedList(int sort)
Definition: remoteutil.cpp:19
MythDate::kTime
@ kTime
Default local time.
Definition: mythdate.h:22
RecordingSelector::OKPressed
void OKPressed(void)
Definition: recordingselector.cpp:283
MythUIImage::SetFilename
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
Definition: mythuiimage.cpp:674
MythUIButtonList::GetItemFirst
MythUIButtonListItem * GetItemFirst() const
Definition: mythuibuttonlist.cpp:1637
mythmainwindow.h
MythUIButtonListItem::setChecked
void setChecked(CheckState state)
Definition: mythuibuttonlist.cpp:3624
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:562
RecordingSelector::m_cancelButton
MythUIButton * m_cancelButton
Definition: recordingselector.h:72
MythUIButtonListItem::NotChecked
@ NotChecked
Definition: mythuibuttonlist.h:46
RecordingSelector::m_archiveList
QList< ArchiveItem * > * m_archiveList
Definition: recordingselector.h:65