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 <libmythbase/mthread.h>
14 #include <libmythbase/mythdate.h>
15 #include <libmythbase/mythdb.h>
17 #include <libmythbase/mythtimer.h>
19 #include <libmythbase/remoteutil.h>
20 #include <libmythbase/stringutil.h>
24 #include <libmythui/mythuibutton.h>
26 #include <libmythui/mythuiimage.h>
27 #include <libmythui/mythuitext.h>
28 
29 // mytharchive
30 #include "archiveutil.h"
31 #include "recordingselector.h"
32 
34 {
35  public:
37  MThread("GetRecordingList"), m_parent(parent)
38  {
39  start();
40  }
41 
42  void run(void) override // MThread
43  {
44  RunProlog();
46  RunEpilog();
47  }
48 
50 };
51 
53 {
54  delete m_recordingList;
55  while (!m_selectedList.isEmpty())
56  delete m_selectedList.takeFirst();
57 }
58 
60 {
61  // Load the theme for this screen
62  bool foundtheme = LoadWindowFromXML("mytharchive-ui.xml", "recording_selector", this);
63  if (!foundtheme)
64  return false;
65 
66  bool err = false;
67  UIUtilE::Assign(this, m_okButton, "ok_button", &err);
68  UIUtilE::Assign(this, m_cancelButton, "cancel_button", &err);
69  UIUtilE::Assign(this, m_categorySelector, "category_selector", &err);
70  UIUtilE::Assign(this, m_recordingButtonList, "recordinglist", &err);
71 
72  UIUtilW::Assign(this, m_titleText, "progtitle", &err);
73  UIUtilW::Assign(this, m_datetimeText, "progdatetime", &err);
74  UIUtilW::Assign(this, m_descriptionText, "progdescription", &err);
75  UIUtilW::Assign(this, m_filesizeText, "filesize", &err);
76  UIUtilW::Assign(this, m_previewImage, "preview_image", &err);
77  UIUtilW::Assign(this, m_cutlistImage, "cutlist_image", &err);
78 
79  if (err)
80  {
81  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'recording_selector'");
82  return false;
83  }
84 
87 
88  new MythUIButtonListItem(m_categorySelector, tr("All Recordings"));
91 
96 
97  if (m_cutlistImage)
99 
100  BuildFocusList();
101 
103 
104  return true;
105 }
106 
108 {
109  QString message = tr("Retrieving Recording List.\nPlease Wait...");
110 
111  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
112 
113  auto *busyPopup = new
114  MythUIBusyDialog(message, popupStack, "recordingselectorbusydialog");
115 
116  if (busyPopup->Create())
117  popupStack->AddScreen(busyPopup, false);
118  else
119  {
120  delete busyPopup;
121  busyPopup = nullptr;
122  }
123 
124  auto *thread = new GetRecordingListThread(this);
125  while (thread->isRunning())
126  {
127  QCoreApplication::processEvents();
128  usleep(2000);
129  }
130 
131  if (!m_recordingList || m_recordingList->empty())
132  {
133  ShowOkPopup(tr("Either you don't have any recordings or "
134  "no recordings are available locally!"));
135  if (busyPopup)
136  busyPopup->Close();
137 
138  Close();
139  return;
140  }
141 
145 
146  if (busyPopup)
147  busyPopup->Close();
148 }
149 
150 bool RecordingSelector::keyPressEvent(QKeyEvent *event)
151 {
152  if (GetFocusWidget()->keyPressEvent(event))
153  return true;
154 
155  QStringList actions;
156  bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
157 
158  for (int i = 0; i < actions.size() && !handled; i++)
159  {
160  const QString& action = actions[i];
161  handled = true;
162 
163  if (action == "MENU")
164  {
165  ShowMenu();
166  }
167  else
168  {
169  handled = false;
170  }
171  }
172 
173  if (!handled && MythScreenType::keyPressEvent(event))
174  handled = true;
175 
176  return handled;
177 }
178 
180 {
181  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
182 
183  auto *menuPopup = new MythDialogBox(tr("Menu"), popupStack, "actionmenu");
184 
185  if (menuPopup->Create())
186  popupStack->AddScreen(menuPopup);
187 
188  menuPopup->SetReturnEvent(this, "action");
189 
190  menuPopup->AddButton(tr("Clear All"), &RecordingSelector::clearAll);
191  menuPopup->AddButton(tr("Select All"), &RecordingSelector::selectAll);
192 }
193 
195 {
196  while (!m_selectedList.isEmpty())
197  m_selectedList.takeFirst();
198  m_selectedList.clear();
199 
200  for (auto *p : *m_recordingList)
201  m_selectedList.append(p);
202 
204 }
205 
207 {
208  while (!m_selectedList.isEmpty())
209  m_selectedList.takeFirst();
210  m_selectedList.clear();
211 
213 }
214 
216 {
218  {
219  int index = m_selectedList.indexOf(item->GetData().value<ProgramInfo *>());
220  if (index != -1)
221  m_selectedList.takeAt(index);
223  }
224  else
225  {
226  int index = m_selectedList.indexOf(item->GetData().value<ProgramInfo *>());
227  if (index == -1)
228  m_selectedList.append(item->GetData().value<ProgramInfo *>());
229 
231  }
232 }
233 
235 {
236  auto *p = item->GetData().value<ProgramInfo *>();
237 
238  if (!p)
239  return;
240 
241  if (m_titleText)
242  m_titleText->SetText(p->GetTitle());
243 
244  if (m_datetimeText)
245  m_datetimeText->SetText(p->GetScheduledStartTime().toLocalTime()
246  .toString("dd MMM yy (hh:mm)"));
247 
248  if (m_descriptionText)
249  {
251  ((!p->GetSubtitle().isEmpty()) ? p->GetSubtitle() + "\n" : "") +
252  p->GetDescription());
253  }
254 
255  if (m_filesizeText)
256  {
257  m_filesizeText->SetText(StringUtil::formatKBytes(p->GetFilesize() / 1024));
258  }
259 
260  if (m_cutlistImage)
261  {
262  if (p->HasCutlist())
263  m_cutlistImage->Show();
264  else
265  m_cutlistImage->Hide();
266  }
267 
268  if (m_previewImage)
269  {
270  // try to locate a preview image
271  if (QFile::exists(p->GetPathname() + ".png"))
272  {
273  m_previewImage->SetFilename(p->GetPathname() + ".png");
274  m_previewImage->Load();
275  }
276  else
277  {
278  m_previewImage->SetFilename("blank.png");
279  m_previewImage->Load();
280  }
281  }
282 }
283 
285 {
286  // loop though selected recordings and add them to the list
287  // remove any items that have been removed from the list
288  QList<ArchiveItem *> tempAList;
289  for (auto *a : std::as_const(*m_archiveList))
290  {
291  bool found = false;
292 
293  for (auto *p : std::as_const(m_selectedList))
294  {
295  if (a->type != "Recording" || a->filename == p->GetPlaybackURL(false, true))
296  {
297  found = true;
298  break;
299  }
300  }
301 
302  if (!found)
303  tempAList.append(a);
304  }
305 
306  for (auto *x : std::as_const(tempAList))
307  m_archiveList->removeAll(x);
308 
309  // remove any items that are already in the list
310  QList<ProgramInfo *> tempSList;
311  for (auto *p : std::as_const(m_selectedList))
312  {
313  for (const auto *a : std::as_const(*m_archiveList))
314  {
315  if (a->filename == p->GetPlaybackURL(false, true))
316  {
317  tempSList.append(p);
318  break;
319  }
320  }
321  }
322 
323  for (auto *x : std::as_const(tempSList))
324  m_selectedList.removeAll(x);
325 
326  // add all that are left
327  for (auto *p : std::as_const(m_selectedList))
328  {
329  auto *a = new ArchiveItem;
330  a->type = "Recording";
331  a->title = p->GetTitle();
332  a->subtitle = p->GetSubtitle();
333  a->description = p->GetDescription();
334  a->startDate = p->GetScheduledStartTime()
335  .toLocalTime().toString("dd MMM yy");
336  a->startTime = p->GetScheduledStartTime()
337  .toLocalTime().toString("(hh:mm)");
338  a->size = p->GetFilesize();
339  a->filename = p->GetPlaybackURL(false, true);
340  a->hasCutlist = p->HasCutlist();
341  a->useCutlist = false;
342  a->duration = 0;
343  a->cutDuration = 0;
344  a->videoWidth = 0;
345  a->videoHeight = 0;
346  a->fileCodec = "";
347  a->videoCodec = "";
348  a->encoderProfile = nullptr;
349  a->editedDetails = false;
350  m_archiveList->append(a);
351  }
352 
353  emit haveResult(true);
354  Close();
355 }
356 
358 {
359  emit haveResult(false);
360  Close();
361 }
362 
364 {
365  if (!m_recordingList || m_recordingList->empty())
366  return;
367 
369 
370  if (m_categorySelector)
371  {
372  for (auto *p : *m_recordingList)
373  {
374  if (p->GetTitle() == m_categorySelector->GetValue() ||
375  m_categorySelector->GetValue() == tr("All Recordings"))
376  {
377  auto* item = new MythUIButtonListItem(
379  p->GetTitle() + " ~ " +
380  p->GetScheduledStartTime().toLocalTime()
381  .toString("dd MMM yy (hh:mm)"));
382  item->setCheckable(true);
383  if (m_selectedList.indexOf(p) != -1)
384  {
385  item->setChecked(MythUIButtonListItem::FullChecked);
386  }
387  else
388  {
389  item->setChecked(MythUIButtonListItem::NotChecked);
390  }
391 
392  QString title = p->GetTitle();
393  QString subtitle = p->GetSubtitle();
394 
395  QDateTime recstartts = p->GetScheduledStartTime();
396  QDateTime recendts = p->GetScheduledEndTime();
397 
398  QString timedate = QString("%1 - %2")
401 
402  uint season = p->GetSeason();
403  uint episode = p->GetEpisode();
404  QString seasone;
405  QString seasonx;
406 
407  if (season && episode)
408  {
409  seasone = QString("s%1e%2")
410  .arg(StringUtil::intToPaddedString(season, 2),
411  StringUtil::intToPaddedString(episode, 2));
412  seasonx = QString("%1x%2")
413  .arg(StringUtil::intToPaddedString(season, 1),
414  StringUtil::intToPaddedString(episode, 2));
415  }
416 
417  item->SetText(title, "title");
418  item->SetText(subtitle, "subtitle");
419  if (subtitle.isEmpty())
420  item->SetText(title, "titlesubtitle");
421  else
422  item->SetText(title + " - \"" + subtitle + '"',
423  "titlesubtitle");
424 
425  item->SetText(timedate, "timedate");
426  item->SetText(p->GetDescription(), "description");
427  item->SetText(StringUtil::formatKBytes(p->GetFilesize() / 1024),
428  "filesize_str");
429 
430  item->SetText(QString::number(season), "season");
431  item->SetText(QString::number(episode), "episode");
432  item->SetText(seasonx, "00x00");
433  item->SetText(seasone, "s00e00");
434 
435  item->DisplayState(p->HasCutlist() ? "yes" : "no", "cutlist");
436 
437  item->SetData(QVariant::fromValue(p));
438  }
439  QCoreApplication::processEvents();
440  }
441  }
442 
445 }
446 
448 {
450  m_categories.clear();
451 
452  if (m_recordingList && !m_recordingList->empty())
453  {
454  auto i = m_recordingList->begin();
455  for ( ; i != m_recordingList->end(); ++i)
456  {
457  ProgramInfo *p = *i;
458  // ignore live tv and deleted recordings
459  if (p->GetRecordingGroup() == "LiveTV" ||
460  p->GetRecordingGroup() == "Deleted")
461  {
462  i = m_recordingList->erase(i);
463  --i;
464  continue;
465  }
466 
467  if (m_categories.indexOf(p->GetTitle()) == -1)
468  m_categories.append(p->GetTitle());
469  }
470  }
471 }
472 
474 {
475  // sort and add categories to selector
476  m_categories.sort();
477 
478  if (m_categorySelector)
479  {
480  new MythUIButtonListItem(m_categorySelector, tr("All Recordings"));
482 
483  for (int x = 0; x < m_categories.count(); x++)
484  {
486  }
487  }
488 }
489 
491 {
493 }
494 
496 {
497  if (!m_recordingList)
498  return;
499 
500  m_selectedList.clear();
501 
502  for (const auto *a : std::as_const(*m_archiveList))
503  {
504  for (auto *p : *m_recordingList)
505  {
506  if (p->GetPlaybackURL(false, true) == a->filename)
507  {
508  if (m_selectedList.indexOf(p) == -1)
509  m_selectedList.append(p);
510  break;
511  }
512 
513  QCoreApplication::processEvents();
514  }
515  }
516 }
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:93
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1614
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:33
mythdb.h
MythUIButtonListItem::FullChecked
@ FullChecked
Definition: mythuibuttonlist.h:48
RecordingSelector::Create
bool Create() override
Definition: recordingselector.cpp:59
GetRecordingListThread::m_parent
RecordingSelector * m_parent
Definition: recordingselector.cpp:49
RecordingSelector::setCategory
void setCategory(MythUIButtonListItem *item)
Definition: recordingselector.cpp:490
MythScreenType::Close
virtual void Close()
Definition: mythscreentype.cpp:384
MythUIImage::Load
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
Definition: mythuiimage.cpp:971
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:42
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
RecordingSelector::ShowMenu
void ShowMenu(void) override
Definition: recordingselector.cpp:179
RecordingSelector::m_categorySelector
MythUIButtonList * m_categorySelector
Definition: recordingselector.h:73
xbmcvfs.exists
bool exists(str path)
Definition: xbmcvfs.py:51
mythdialogbox.h
MythScreenStack
Definition: mythscreenstack.h:16
RecordingSelector::toggleSelected
void toggleSelected(MythUIButtonListItem *item)
Definition: recordingselector.cpp:215
RecordingSelector::keyPressEvent
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
Definition: recordingselector.cpp:150
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:111
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
recordingselector.h
RecordingSelector::getRecordingList
void getRecordingList(void)
Definition: recordingselector.cpp:447
RecordingSelector::selectAll
void selectAll(void)
Definition: recordingselector.cpp:194
ArchiveItem::type
QString type
Definition: archiveutil.h:53
RecordingSelector::clearAll
void clearAll(void)
Definition: recordingselector.cpp:206
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:1144
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:1111
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:107
archiveutil.h
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:116
RecordingSelector::titleChanged
void titleChanged(MythUIButtonListItem *item)
Definition: recordingselector.cpp:234
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:165
RecordingSelector::m_selectedList
QList< ProgramInfo * > m_selectedList
Definition: recordingselector.h:67
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:204
stringutil.h
RecordingSelector::updateRecordingList
void updateRecordingList(void)
Definition: recordingselector.cpp:363
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:495
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:27
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3715
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:357
MythUIType::Hide
void Hide(void)
Definition: mythuitype.cpp:1139
RecordingSelector::updateCategorySelector
void updateCategorySelector(void)
Definition: recordingselector.cpp:473
StringUtil::formatKBytes
MBASE_PUBLIC QString formatKBytes(int64_t sizeKB, int prec=1)
Definition: stringutil.cpp:357
MythUIButtonListItem::NotChecked
@ NotChecked
Definition: mythuibuttonlist.h:46
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:402
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:701
MythUIButtonList::GetValue
virtual QString GetValue() const
Definition: mythuibuttonlist.cpp:1633
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
MythUIButtonListItem::state
CheckState state() const
Definition: mythuibuttonlist.cpp:3669
RecordingSelector::~RecordingSelector
~RecordingSelector(void) override
Definition: recordingselector.cpp:52
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:1581
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:322
RecordingSelector::m_descriptionText
MythUIText * m_descriptionText
Definition: recordingselector.h:77
GetRecordingListThread::GetRecordingListThread
GetRecordingListThread(RecordingSelector *parent)
Definition: recordingselector.cpp:36
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:284
MythUIImage::SetFilename
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
Definition: mythuiimage.cpp:677
MythUIButtonList::GetItemFirst
MythUIButtonListItem * GetItemFirst() const
Definition: mythuibuttonlist.cpp:1660
mythmainwindow.h
MythUIButtonListItem::setChecked
void setChecked(CheckState state)
Definition: mythuibuttonlist.cpp:3679
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:566
RecordingSelector::m_cancelButton
MythUIButton * m_cancelButton
Definition: recordingselector.h:72
uint
unsigned int uint
Definition: freesurround.h:24
RecordingSelector::m_archiveList
QList< ArchiveItem * > * m_archiveList
Definition: recordingselector.h:65