MythTV master
recordingselector.cpp
Go to the documentation of this file.
1
2// c++
3#include <cstdlib>
4#include <thread>
5
6// qt
7#include <QApplication>
8#include <QDir>
9#include <QKeyEvent>
10#include <QTimer>
11
12// mythtv
13#include <libmythbase/mthread.h>
15#include <libmythbase/mythdb.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 protected:
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
100
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 {
119 popupStack->AddScreen(busyPopup, false);
120 }
121 else
122 {
123 delete busyPopup;
124 busyPopup = nullptr;
125 }
126
127 auto *thread = new GetRecordingListThread(this);
128 while (thread->isRunning())
129 {
130 QCoreApplication::processEvents();
131 std::this_thread::sleep_for(2ms);
132 }
133
134 if (!m_recordingList || m_recordingList->empty())
135 {
136 ShowOkPopup(tr("Either you don't have any recordings or "
137 "no recordings are available locally!"));
138 if (busyPopup)
139 busyPopup->Close();
140
141 Close();
142 return;
143 }
144
148
149 if (busyPopup)
150 busyPopup->Close();
151}
152
154{
155 if (GetFocusWidget()->keyPressEvent(event))
156 return true;
157
158 QStringList actions;
159 bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
160
161 for (int i = 0; i < actions.size() && !handled; i++)
162 {
163 const QString& action = actions[i];
164 handled = true;
165
166 if (action == "MENU")
167 {
168 ShowMenu();
169 }
170 else
171 {
172 handled = false;
173 }
174 }
175
176 if (!handled && MythScreenType::keyPressEvent(event))
177 handled = true;
178
179 return handled;
180}
181
183{
184 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
185
186 auto *menuPopup = new MythDialogBox(tr("Menu"), popupStack, "actionmenu");
187
188 if (menuPopup->Create())
189 popupStack->AddScreen(menuPopup);
190
191 menuPopup->SetReturnEvent(this, "action");
192
193 menuPopup->AddButton(tr("Clear All"), &RecordingSelector::clearAll);
194 menuPopup->AddButton(tr("Select All"), &RecordingSelector::selectAll);
195}
196
198{
199 while (!m_selectedList.isEmpty())
200 m_selectedList.takeFirst();
201 m_selectedList.clear();
202
203 for (auto *p : *m_recordingList)
204 m_selectedList.append(p);
205
207}
208
210{
211 while (!m_selectedList.isEmpty())
212 m_selectedList.takeFirst();
213 m_selectedList.clear();
214
216}
217
219{
221 {
222 int index = m_selectedList.indexOf(item->GetData().value<ProgramInfo *>());
223 if (index != -1)
224 m_selectedList.takeAt(index);
226 }
227 else
228 {
229 int index = m_selectedList.indexOf(item->GetData().value<ProgramInfo *>());
230 if (index == -1)
231 m_selectedList.append(item->GetData().value<ProgramInfo *>());
232
234 }
235}
236
238{
239 auto *p = item->GetData().value<ProgramInfo *>();
240
241 if (!p)
242 return;
243
244 if (m_titleText)
245 m_titleText->SetText(p->GetTitle());
246
247 if (m_datetimeText)
248 m_datetimeText->SetText(p->GetScheduledStartTime().toLocalTime()
249 .toString("dd MMM yy (hh:mm)"));
250
252 {
254 ((!p->GetSubtitle().isEmpty()) ? p->GetSubtitle() + "\n" : "") +
255 p->GetDescription());
256 }
257
258 if (m_filesizeText)
259 {
260 m_filesizeText->SetText(StringUtil::formatKBytes(p->GetFilesize() / 1024));
261 }
262
263 if (m_cutlistImage)
264 {
265 if (p->HasCutlist())
267 else
269 }
270
271 if (m_previewImage)
272 {
273 // try to locate a preview image
274 if (QFile::exists(p->GetPathname() + ".png"))
275 {
276 m_previewImage->SetFilename(p->GetPathname() + ".png");
278 }
279 else
280 {
281 m_previewImage->SetFilename("blank.png");
283 }
284 }
285}
286
288{
289 // loop though selected recordings and add them to the list
290 // remove any items that have been removed from the list
291 QList<ArchiveItem *> tempAList;
292 for (auto *a : std::as_const(*m_archiveList))
293 {
294 bool found = false;
295
296 for (auto *p : std::as_const(m_selectedList))
297 {
298 if (a->type != "Recording" || a->filename == p->GetPlaybackURL(false, true))
299 {
300 found = true;
301 break;
302 }
303 }
304
305 if (!found)
306 tempAList.append(a);
307 }
308
309 for (auto *x : std::as_const(tempAList))
310 m_archiveList->removeAll(x);
311
312 // remove any items that are already in the list
313 QList<ProgramInfo *> tempSList;
314 for (auto *p : std::as_const(m_selectedList))
315 {
316 for (const auto *a : std::as_const(*m_archiveList))
317 {
318 if (a->filename == p->GetPlaybackURL(false, true))
319 {
320 tempSList.append(p);
321 break;
322 }
323 }
324 }
325
326 for (auto *x : std::as_const(tempSList))
327 m_selectedList.removeAll(x);
328
329 // add all that are left
330 for (auto *p : std::as_const(m_selectedList))
331 {
332 auto *a = new ArchiveItem;
333 a->type = "Recording";
334 a->title = p->GetTitle();
335 a->subtitle = p->GetSubtitle();
336 a->description = p->GetDescription();
337 a->startDate = p->GetScheduledStartTime()
338 .toLocalTime().toString("dd MMM yy");
339 a->startTime = p->GetScheduledStartTime()
340 .toLocalTime().toString("(hh:mm)");
341 a->size = p->GetFilesize();
342 a->filename = p->GetPlaybackURL(false, true);
343 a->hasCutlist = p->HasCutlist();
344 a->useCutlist = false;
345 a->duration = 0;
346 a->cutDuration = 0;
347 a->videoWidth = 0;
348 a->videoHeight = 0;
349 a->fileCodec = "";
350 a->videoCodec = "";
351 a->encoderProfile = nullptr;
352 a->editedDetails = false;
353 m_archiveList->append(a);
354 }
355
356 emit haveResult(true);
357 Close();
358}
359
361{
362 emit haveResult(false);
363 Close();
364}
365
367{
368 if (!m_recordingList || m_recordingList->empty())
369 return;
370
372
374 {
375 for (auto *p : *m_recordingList)
376 {
377 if (p->GetTitle() == m_categorySelector->GetValue() ||
378 m_categorySelector->GetValue() == tr("All Recordings"))
379 {
380 auto* item = new MythUIButtonListItem(
382 p->GetTitle() + " ~ " +
383 p->GetScheduledStartTime().toLocalTime()
384 .toString("dd MMM yy (hh:mm)"));
385 item->setCheckable(true);
386 if (m_selectedList.indexOf(p) != -1)
387 {
388 item->setChecked(MythUIButtonListItem::FullChecked);
389 }
390 else
391 {
392 item->setChecked(MythUIButtonListItem::NotChecked);
393 }
394
395 QString title = p->GetTitle();
396 QString subtitle = p->GetSubtitle();
397
398 QDateTime recstartts = p->GetScheduledStartTime();
399 QDateTime recendts = p->GetScheduledEndTime();
400
401 QString timedate = QString("%1 - %2")
404
405 uint season = p->GetSeason();
406 uint episode = p->GetEpisode();
407 QString seasone;
408 QString seasonx;
409
410 if (season && episode)
411 {
412 seasone = QString("s%1e%2")
413 .arg(StringUtil::intToPaddedString(season, 2),
415 seasonx = QString("%1x%2")
416 .arg(StringUtil::intToPaddedString(season, 1),
418 }
419
420 item->SetText(title, "title");
421 item->SetText(subtitle, "subtitle");
422 if (subtitle.isEmpty())
423 item->SetText(title, "titlesubtitle");
424 else
425 item->SetText(title + " - \"" + subtitle + '"',
426 "titlesubtitle");
427
428 item->SetText(timedate, "timedate");
429 item->SetText(p->GetDescription(), "description");
430 item->SetText(StringUtil::formatKBytes(p->GetFilesize() / 1024),
431 "filesize_str");
432
433 item->SetText(QString::number(season), "season");
434 item->SetText(QString::number(episode), "episode");
435 item->SetText(seasonx, "00x00");
436 item->SetText(seasone, "s00e00");
437
438 item->DisplayState(p->HasCutlist() ? "yes" : "no", "cutlist");
439
440 item->SetData(QVariant::fromValue(p));
441 }
442 QCoreApplication::processEvents();
443 }
444 }
445
448}
449
451{
453 m_categories.clear();
454
455 if (m_recordingList && !m_recordingList->empty())
456 {
457 auto i = m_recordingList->begin();
458 for ( ; i != m_recordingList->end(); ++i)
459 {
460 ProgramInfo *p = *i;
461 // ignore live tv and deleted recordings
462 if (p->GetRecordingGroup() == "LiveTV" ||
463 p->GetRecordingGroup() == "Deleted")
464 {
465 i = m_recordingList->erase(i);
466 --i;
467 continue;
468 }
469
470 if (m_categories.indexOf(p->GetTitle()) == -1)
471 m_categories.append(p->GetTitle());
472 }
473 }
474}
475
477{
478 // sort and add categories to selector
479 m_categories.sort();
480
482 {
483 new MythUIButtonListItem(m_categorySelector, tr("All Recordings"));
485
486 for (int x = 0; x < m_categories.count(); x++)
487 {
489 }
490 }
491}
492
494{
496}
497
499{
500 if (!m_recordingList)
501 return;
502
503 m_selectedList.clear();
504
505 for (const auto *a : std::as_const(*m_archiveList))
506 {
507 for (auto *p : *m_recordingList)
508 {
509 if (p->GetPlaybackURL(false, true) == a->filename)
510 {
511 if (m_selectedList.indexOf(p) == -1)
512 m_selectedList.append(p);
513 break;
514 }
515
516 QCoreApplication::processEvents();
517 }
518 }
519}
RecordingSelector * m_parent
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
GetRecordingListThread(RecordingSelector *parent)
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:180
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:267
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:193
Basic menu dialog, message and a list of options.
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
MythScreenStack * GetStack(const QString &Stackname)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void BuildFocusList(void)
MythUIType * GetFocusWidget(void) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
bool SetFocusWidget(MythUIType *widget=nullptr)
virtual void Close()
CheckState state() const
void setChecked(CheckState state)
virtual QString GetValue() const
MythUIButtonListItem * GetItemCurrent() const
void SetItemCurrent(MythUIButtonListItem *item)
MythUIButtonListItem * GetItemFirst() const
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
void itemClicked(MythUIButtonListItem *item)
void itemSelected(MythUIButtonListItem *item)
void Clicked()
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
void Hide(void)
void Show(void)
Holds information on recordings and videos.
Definition: programinfo.h:74
MythUIText * m_descriptionText
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
void toggleSelected(MythUIButtonListItem *item)
QList< ProgramInfo * > m_selectedList
bool Create() override
void haveResult(bool ok)
void updateCategorySelector(void)
MythUIText * m_datetimeText
friend class GetRecordingListThread
void titleChanged(MythUIButtonListItem *item)
void setCategory(MythUIButtonListItem *item)
MythUIImage * m_cutlistImage
MythUIButtonList * m_categorySelector
std::vector< ProgramInfo * > * m_recordingList
MythUIButton * m_cancelButton
~RecordingSelector(void) override
QStringList m_categories
QList< ArchiveItem * > * m_archiveList
void updateRecordingList(void)
MythUIImage * m_previewImage
MythUIButton * m_okButton
MythUIButtonList * m_recordingButtonList
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
MythUIText * m_filesizeText
void ShowMenu(void) override
MythUIText * m_titleText
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
unsigned int uint
Definition: compat.h:60
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:93
@ kDateTimeFull
Default local time.
Definition: mythdate.h:23
@ kTime
Default local time.
Definition: mythdate.h:22
QString intToPaddedString(int n, int width=2)
Creates a zero padded string representation of an integer.
Definition: stringutil.h:31
MBASE_PUBLIC QString formatKBytes(int64_t sizeKB, int prec=1)
Definition: stringutil.cpp:281
bool exists(str path)
Definition: xbmcvfs.py:51
std::vector< ProgramInfo * > * RemoteGetRecordedList(int sort)
QString type
Definition: archiveutil.h:53
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27