MythTV master
statusbox.cpp
Go to the documentation of this file.
1// Qt
2#include <QHostAddress>
3#include <QNetworkInterface>
4
5// MythTV
10#include "libmythbase/mythdb.h"
13#include "libmythbase/mythversion.h"
15#include "libmythtv/cardutil.h"
17#include "libmythtv/jobqueue.h"
20#include "libmythtv/tv.h"
29
30// MythFrontend
31#include "statusbox.h"
32
33struct LogLine {
34 QString m_line;
35 QString m_detail;
36 QString m_help;
37 QString m_helpdetail;
38 QString m_data;
39 QString m_state;
40};
41
42void StatusBoxItem::Start(std::chrono::seconds Interval)
43{
44 connect(this, &QTimer::timeout, [this]() { emit UpdateRequired(this); });
45 start(Interval);
46}
47
58 : MythScreenType(parent, "StatusBox")
59{
60 m_minLevel = gCoreContext->GetNumSetting("LogDefaultView",5);
61
62 QStringList strlist;
63 strlist << "QUERY_IS_ACTIVE_BACKEND";
64 strlist << gCoreContext->GetHostName();
65
67
68 m_isBackendActive = (strlist[0] == "TRUE");
69 m_popupStack = GetMythMainWindow()->GetStack("popup stack");
70}
71
73{
74 if (m_logList)
75 gCoreContext->SaveSetting("StatusBoxItemCurrent",
77}
78
80{
81 if (!LoadWindowFromXML("status-ui.xml", "status", this))
82 return false;
83
84 m_categoryList = dynamic_cast<MythUIButtonList *>(GetChild("category"));
85 m_logList = dynamic_cast<MythUIButtonList *>(GetChild("log"));
86
87 m_iconState = dynamic_cast<MythUIStateType *>(GetChild("icon"));
88 m_helpText = dynamic_cast<MythUIText *>(GetChild("helptext"));
89 m_justHelpText = dynamic_cast<MythUIText *>(GetChild("justhelptext"));
90
92 {
93 LOG(VB_GENERAL, LOG_ERR, "StatusBox, theme is missing "
94 "required elements");
95 return false;
96 }
97
103 this, &StatusBox::clicked);
104
106 return true;
107}
108
110{
111 auto *item = new MythUIButtonListItem(m_categoryList, tr("Listings Status"),
113 item->DisplayState("listings", "icon");
114
115 item = new MythUIButtonListItem(m_categoryList, tr("Schedule Status"),
117 item->DisplayState("schedule", "icon");
118
119 item = new MythUIButtonListItem(m_categoryList, tr("Input Status"),
121 item->DisplayState("tuner", "icon");
122
123 item = new MythUIButtonListItem(m_categoryList, tr("Job Queue"),
125 item->DisplayState("jobqueue", "icon");
126
127 item = new MythUIButtonListItem(m_categoryList, tr("Video decoders"),
129 item->DisplayState("decoders", "icon");
130
131 item = new MythUIButtonListItem(m_categoryList, tr("Display"),
133 item->DisplayState("display", "icon");
134
135 item = new MythUIButtonListItem(m_categoryList, tr("Rendering"),
137 item->DisplayState("render", "icon");
138
139 item = new MythUIButtonListItem(m_categoryList, tr("Machine Status"),
141 item->DisplayState("machine", "icon");
142
143 item = new MythUIButtonListItem(m_categoryList, tr("AutoExpire List"),
144 qOverload<>(&StatusBox::doAutoExpireList));
145 item->DisplayState("autoexpire", "icon");
146
147 int itemCurrent = gCoreContext->GetNumSetting("StatusBoxItemCurrent", 0);
148 m_categoryList->SetItemCurrent(itemCurrent);
149}
150
152 const QString & help,
153 const QString & detail,
154 const QString & helpdetail,
155 const QString & state,
156 const QString & data)
157{
158 LogLine logline;
159 logline.m_line = line;
160
161 if (detail.isEmpty())
162 logline.m_detail = line;
163 else
164 logline.m_detail = detail;
165
166 if (help.isEmpty())
167 logline.m_help = logline.m_detail;
168 else
169 logline.m_help = help;
170
171 if (helpdetail.isEmpty())
172 logline.m_helpdetail = logline.m_detail;
173 else
174 logline.m_helpdetail = helpdetail;
175
176 logline.m_state = state;
177 logline.m_data = data;
178
179 auto *item = new StatusBoxItem(m_logList, line, QVariant::fromValue(logline));
180 if (logline.m_state.isEmpty())
181 logline.m_state = "normal";
182
183 item->SetFontState(logline.m_state);
184 item->DisplayState(logline.m_state, "status");
185 item->SetText(logline.m_detail, "detail");
186 return item;
187}
188
189bool StatusBox::keyPressEvent(QKeyEvent *event)
190{
191 if (GetFocusWidget()->keyPressEvent(event))
192 return true;
193
194 QStringList actions;
195 bool handled = GetMythMainWindow()->TranslateKeyPress("Status", event, actions);
196
197#if 0
198 for (int i = 0; i < actions.size() && !handled; ++i)
199 {
200 QString action = actions[i];
201 handled = true;
202
203 if (action == "MENU")
204 {
205 }
206 else
207 handled = false;
208 }
209#endif
210
211 if (!handled && MythScreenType::keyPressEvent(event))
212 handled = true;
213
214 return handled;
215}
216
218{
219 if (!item || GetFocusWidget() != m_logList)
220 return;
221
222 auto logline = item->GetData().value<LogLine>();
223 if (m_helpText)
224 m_helpText->SetText(logline.m_helpdetail);
225 if (m_justHelpText)
226 m_justHelpText->SetText(logline.m_help);
227}
228
230{
231 if (!item)
232 return;
233
234 disconnect(this, &StatusBox::updateLog,nullptr,nullptr);
235
236 if (item->GetData().value<MythUICallbackMF>())
237 {
238 connect(this, &StatusBox::updateLog,
239 item->GetData().value<MythUICallbackMF>());
240 emit updateLog();
241 }
242 else if (item->GetData().value<MythUICallbackMFc>())
243 {
244 connect(this, &StatusBox::updateLog,
245 item->GetData().value<MythUICallbackMFc>());
246 emit updateLog();
247 }
248}
249
251{
252 if (!item)
253 return;
254
255 auto logline = item->GetData().value<LogLine>();
256
258 QString currentItem;
259 if (currentButton)
260 currentItem = currentButton->GetText();
261
262 // FIXME: Comparisons against strings here is not great, changing names
263 // breaks everything and it's inefficient
264 if (currentItem == tr("Job Queue"))
265 {
266 int jobStatus = JobQueue::GetJobStatus(logline.m_data.toInt());
267
268 if (jobStatus == JOB_QUEUED)
269 {
270 QString message = tr("Delete Job?");
271
272 auto *confirmPopup =
274
275 confirmPopup->SetReturnEvent(this, "JobDelete");
276 confirmPopup->SetData(logline.m_data);
277
278 if (confirmPopup->Create())
279 m_popupStack->AddScreen(confirmPopup, false);
280 }
281 else if ((jobStatus == JOB_PENDING) ||
282 (jobStatus == JOB_STARTING) ||
283 (jobStatus == JOB_RUNNING) ||
284 (jobStatus == JOB_PAUSED))
285 {
286 QString label = tr("Job Queue Actions:");
287
288 auto *menuPopup = new MythDialogBox(label, m_popupStack,
289 "statusboxpopup");
290
291 if (menuPopup->Create())
292 m_popupStack->AddScreen(menuPopup, false);
293
294 menuPopup->SetReturnEvent(this, "JobModify");
295
296 QVariant data = QVariant::fromValue(logline.m_data);
297
298 if (jobStatus == JOB_PAUSED)
299 menuPopup->AddButtonV(tr("Resume"), data);
300 else
301 menuPopup->AddButtonV(tr("Pause"), data);
302 menuPopup->AddButtonV(tr("Stop"), data);
303 menuPopup->AddButtonV(tr("No Change"), data);
304 }
305 else if (jobStatus & JOB_DONE)
306 {
307 QString message = tr("Requeue Job?");
308
309 auto *confirmPopup =
311
312 confirmPopup->SetReturnEvent(this, "JobRequeue");
313 confirmPopup->SetData(logline.m_data);
314
315 if (confirmPopup->Create())
316 m_popupStack->AddScreen(confirmPopup, false);
317 }
318 }
319 else if (currentItem == tr("AutoExpire List"))
320 {
322
323 if (rec)
324 {
325 QString label = tr("AutoExpire Actions:");
326
327 auto *menuPopup = new MythDialogBox(label, m_popupStack,
328 "statusboxpopup");
329
330 if (menuPopup->Create())
331 m_popupStack->AddScreen(menuPopup, false);
332
333 menuPopup->SetReturnEvent(this, "AutoExpireManage");
334
335 menuPopup->AddButtonV(tr("Delete Now"), QVariant::fromValue(rec));
336 if ((rec)->GetRecordingGroup() == "LiveTV")
337 {
338 menuPopup->AddButtonV(tr("Move to Default group"),
339 QVariant::fromValue(rec));
340 }
341 else if ((rec)->GetRecordingGroup() == "Deleted")
342 {
343 menuPopup->AddButtonV(tr("Undelete"), QVariant::fromValue(rec));
344 }
345 else
346 {
347 menuPopup->AddButtonV(tr("Disable AutoExpire"),
348 QVariant::fromValue(rec));
349 }
350 menuPopup->AddButtonV(tr("No Change"), QVariant::fromValue(rec));
351
352 }
353 }
354}
355
356void StatusBox::customEvent(QEvent *event)
357{
358 if (event->type() == DialogCompletionEvent::kEventType)
359 {
360 auto *dce = (DialogCompletionEvent*)(event);
361
362 QString resultid = dce->GetId();
363 int buttonnum = dce->GetResult();
364
365 if (resultid == "JobDelete")
366 {
367 if (buttonnum == 1)
368 {
369 int jobID = dce->GetData().toInt();
371
373 }
374 }
375 else if (resultid == "JobRequeue")
376 {
377 if (buttonnum == 1)
378 {
379 int jobID = dce->GetData().toInt();
380 JobQueue::ChangeJobStatus(jobID, JOB_QUEUED);
382 }
383 }
384 else if (resultid == "JobModify")
385 {
386 int jobID = dce->GetData().toInt();
387 if (buttonnum == 0)
388 {
389 if (JobQueue::GetJobStatus(jobID) == JOB_PAUSED)
391 else
393 }
394 else if (buttonnum == 1)
395 {
397 }
398
400 }
401 else if (resultid == "AutoExpireManage")
402 {
403 auto* rec = dce->GetData().value<ProgramInfo*>();
404
405 // button 2 is "No Change"
406 if (!rec || buttonnum == 2)
407 return;
408
409 // button 1 is "Delete Now"
410 if ((buttonnum == 0) && rec->QueryIsDeleteCandidate())
411 {
412 if (!RemoteDeleteRecording(rec->GetRecordingID(),
413 false, false))
414 {
415 LOG(VB_GENERAL, LOG_ERR, QString("Failed to delete recording: %1").arg(rec->GetTitle()));
416 return;
417 }
418 }
419 // button 1 is "Move To Default Group" or "UnDelete" or "Disable AutoExpire"
420 else if (buttonnum == 1)
421 {
422 if ((rec)->GetRecordingGroup() == "Deleted")
423 {
424 RemoteUndeleteRecording(rec->GetRecordingID());
425 }
426 else
427 {
428 rec->SaveAutoExpire(kDisableAutoExpire);
429
430 if ((rec)->GetRecordingGroup() == "LiveTV")
431 {
432 RecordingInfo ri(*rec);
434 *rec = ri;
435 }
436 }
437 }
438
439 // remove the changed recording from the expire list
441 m_expList.erase(m_expList.begin() + m_logList->GetCurrentPos());
442
443 int pos = m_logList->GetCurrentPos();
444 int topPos = m_logList->GetTopItemPos();
445 doAutoExpireList(false);
446 m_logList->SetItemCurrent(pos, topPos);
447 }
448
449 }
450}
451
453{
454 if (m_iconState)
455 m_iconState->DisplayState("listings");
456 m_logList->Reset();
457
458 QString helpmsg(tr("Listings Status shows the latest "
459 "status information from "
460 "mythfilldatabase"));
461 if (m_helpText)
462 m_helpText->SetText(helpmsg);
463 if (m_justHelpText)
464 m_justHelpText->SetText(helpmsg);
465
466 QDateTime mfdLastRunStart;
467 QDateTime mfdLastRunEnd;
468 QDateTime mfdNextRunStart;
469 QString mfdLastRunStatus;
470 QDateTime qdtNow;
471 QDateTime GuideDataThrough;
472
473 qdtNow = MythDate::current();
474
476 query.prepare("SELECT max(endtime) FROM program WHERE manualid=0;");
477
478 if (query.exec() && query.next())
479 GuideDataThrough = MythDate::fromString(query.value(0).toString());
480
481 QString tmp = gCoreContext->GetSetting("mythfilldatabaseLastRunStart");
482 mfdLastRunStart = MythDate::fromString(tmp);
483 tmp = gCoreContext->GetSetting("mythfilldatabaseLastRunEnd");
484 mfdLastRunEnd = MythDate::fromString(tmp);
485 tmp = gCoreContext->GetSetting("MythFillSuggestedRunTime");
486 mfdNextRunStart = MythDate::fromString(tmp);
487
488 mfdLastRunStatus = gCoreContext->GetSetting("mythfilldatabaseLastRunStatus");
489
490 AddLogLine(tr("Mythfrontend version: %1 (%2)")
492 helpmsg);
493 AddLogLine(tr("Database schema version: %1").arg(gCoreContext->GetSetting("DBSchemaVer")));
494 AddLogLine(tr("Last mythfilldatabase guide update:"), helpmsg);
495 tmp = tr("Started: %1").arg(
497 mfdLastRunStart, MythDate::kDateTimeFull | MythDate::kSimplify));
498 AddLogLine(tmp, helpmsg);
499
500 if (mfdLastRunEnd >= mfdLastRunStart)
501 {
502 tmp = tr("Finished: %1")
504 mfdLastRunEnd,
506 AddLogLine(tmp, helpmsg);
507 }
508
509 AddLogLine(tr("Result: %1").arg(mfdLastRunStatus), helpmsg);
510
511
512 if (mfdNextRunStart >= mfdLastRunStart)
513 {
514 tmp = tr("Suggested Next: %1")
516 mfdNextRunStart,
518 AddLogLine(tmp, helpmsg);
519 }
520
521 int DaysOfData = qdtNow.daysTo(GuideDataThrough);
522
523 if (GuideDataThrough.isNull())
524 {
525 AddLogLine(tr("There's no guide data available!"), helpmsg,
526 "", "warning");
527 AddLogLine(tr("Have you run mythfilldatabase?"), helpmsg,
528 "", "warning");
529 }
530 else
531 {
533 tr("There is guide data until %1")
535 GuideDataThrough,
537
538 AddLogLine(QString("(%1).").arg(tr("%n day(s)", "", DaysOfData)),
539 helpmsg);
540 }
541
542 if (DaysOfData <= 3)
543 AddLogLine(tr("WARNING: is mythfilldatabase running?"), helpmsg,
544 "", "", "warning");
545}
546
548{
549 if (m_iconState)
550 m_iconState->DisplayState("schedule");
551 m_logList->Reset();
552
553 QString helpmsg(tr("Schedule Status shows current statistics "
554 "from the scheduler."));
555 if (m_helpText)
556 m_helpText->SetText(helpmsg);
557 if (m_justHelpText)
558 m_justHelpText->SetText(helpmsg);
559
561
562 query.prepare("SELECT COUNT(*) FROM record WHERE type = :TEMPLATE");
563 query.bindValue(":TEMPLATE", kTemplateRecord);
564 if (query.exec() && query.next())
565 {
566 QString rules = tr("%n template rule(s) (is) defined", "",
567 query.value(0).toInt());
568 AddLogLine(rules, helpmsg);
569 }
570 else
571 {
572 MythDB::DBError("StatusBox::doScheduleStatus()", query);
573 return;
574 }
575
576 query.prepare("SELECT COUNT(*) FROM record "
577 "WHERE type <> :TEMPLATE AND search = :NOSEARCH");
578 query.bindValue(":TEMPLATE", kTemplateRecord);
579 query.bindValue(":NOSEARCH", kNoSearch);
580 if (query.exec() && query.next())
581 {
582 QString rules = tr("%n standard rule(s) (is) defined", "",
583 query.value(0).toInt());
584 AddLogLine(rules, helpmsg);
585 }
586 else
587 {
588 MythDB::DBError("StatusBox::doScheduleStatus()", query);
589 return;
590 }
591
592 query.prepare("SELECT COUNT(*) FROM record WHERE search > :NOSEARCH");
593 query.bindValue(":NOSEARCH", kNoSearch);
594 if (query.exec() && query.next())
595 {
596 QString rules = tr("%n search rule(s) are defined", "",
597 query.value(0).toInt());
598 AddLogLine(rules, helpmsg);
599 }
600 else
601 {
602 MythDB::DBError("StatusBox::doScheduleStatus()", query);
603 return;
604 }
605
606 QMap<RecStatus::Type, int> statusMatch;
607 QMap<RecStatus::Type, QString> statusText;
608 QMap<int, int> sourceMatch;
609 QMap<int, QString> sourceText;
610 QMap<int, int> cardMatch;
611 QMap<int, QString> cardText;
612 QMap<int, int> cardParent;
613 QMap<int, bool> cardSchedGroup;
614 QString tmpstr;
615 int maxSource = 0;
616 int maxCard = 0;
617 int lowerpriority = 0;
618 int hdflag = 0;
619
620 query.prepare("SELECT MAX(sourceid) FROM videosource");
621 if (query.exec())
622 {
623 if (query.next())
624 maxSource = query.value(0).toInt();
625 }
626
627 query.prepare("SELECT sourceid,name FROM videosource");
628 if (query.exec())
629 {
630 while (query.next())
631 sourceText[query.value(0).toInt()] = query.value(1).toString();
632 }
633
634 query.prepare("SELECT MAX(cardid) FROM capturecard");
635 if (query.exec())
636 {
637 if (query.next())
638 maxCard = query.value(0).toInt();
639 }
640
641 query.prepare("SELECT cardid, inputname, displayname, parentid, "
642 " schedgroup "
643 "FROM capturecard");
644 if (query.exec())
645 {
646 while (query.next())
647 {
648 int inputid = query.value(0).toInt();
649 cardText[inputid] = query.value(2).toString();
650 if (cardText[inputid].isEmpty())
651 cardText[inputid] = QString::number(query.value(1).toInt());
652 cardParent[inputid] = query.value(3).toInt();
653 cardSchedGroup[inputid] = query.value(4).toBool();
654 }
655 }
656
657 ProgramList schedList;
658 LoadFromScheduler(schedList);
659
660 tmpstr = tr("%n matching showing(s)", "", schedList.size());
661 AddLogLine(tmpstr, helpmsg);
662
663 for (auto *s : schedList)
664 {
665 const RecStatus::Type recstatus = s->GetRecordingStatus();
666
667 if (statusMatch[recstatus] < 1)
668 {
669 statusText[recstatus] = RecStatus::toString(
670 recstatus, s->GetRecordingRuleType());
671 }
672
673 ++statusMatch[recstatus];
674
675 if (recstatus == RecStatus::WillRecord ||
676 recstatus == RecStatus::Pending ||
677 recstatus == RecStatus::Recording ||
678 recstatus == RecStatus::Tuning ||
679 recstatus == RecStatus::Failing)
680 {
681 ++sourceMatch[s->GetSourceID()];
682 int inputid = s->GetInputID();
683 // When schedgroup is used, always attribute recordings to
684 // the parent inputs.
685 if (cardParent[inputid] && cardSchedGroup[cardParent[inputid]])
686 inputid = cardParent[inputid];
687 ++cardMatch[inputid];
688 if (s->GetRecordingPriority2() < 0)
689 ++lowerpriority;
690 if (s->GetVideoProperties() & VID_HDTV)
691 ++hdflag;
692 }
693 }
694
695// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
696#define ADD_STATUS_LOG_LINE(rtype, fstate) \
697 do { \
698 if (statusMatch[rtype] > 0) \
699 { \
700 tmpstr = QString("%1 %2").arg(statusMatch[rtype]) \
701 .arg(statusText[rtype]); \
702 AddLogLine(tmpstr, helpmsg, tmpstr, tmpstr, fstate);\
703 } \
704 } while (false)
715
716 QString willrec = statusText[RecStatus::WillRecord];
717
718 if (lowerpriority > 0)
719 {
720 tmpstr = QString("%1 %2 %3").arg(QString::number(lowerpriority),
721 willrec, tr("with lower priority"));
722 AddLogLine(tmpstr, helpmsg, tmpstr, tmpstr, "warning");
723 }
724 if (hdflag > 0)
725 {
726 tmpstr = QString("%1 %2 %3").arg(QString::number(hdflag),
727 willrec, tr("marked as HDTV"));
728 AddLogLine(tmpstr, helpmsg);
729 }
730 for (int i = 1; i <= maxSource; ++i)
731 {
732 if (sourceMatch[i] > 0)
733 {
734 tmpstr = QString("%1 %2 %3 %4 \"%5\"")
735 .arg(QString::number(sourceMatch[i]), willrec,
736 tr("from source"), QString::number(i), sourceText[i]);
737 AddLogLine(tmpstr, helpmsg);
738 }
739 }
740 for (int i = 1; i <= maxCard; ++i)
741 {
742 if (cardMatch[i] > 0)
743 {
744 tmpstr = QString("%1 %2 %3 %4 \"%5\"")
745 .arg(QString::number(cardMatch[i]), willrec,
746 tr("on input"), QString::number(i), cardText[i]);
747 AddLogLine(tmpstr, helpmsg);
748 }
749 }
750}
751
753{
754 struct info
755 {
756 int m_errored {0};
757 int m_unavailable {0};
758 int m_sleeping {0};
759 int m_recording {0};
760 int m_livetv {0};
761 int m_available {0};
762 QStringList m_recordings;
763 };
764 QMap<QString, struct info> info;
765 QStringList inputnames;
766
767 if (m_iconState)
768 m_iconState->DisplayState("tuner");
769 m_logList->Reset();
770
771 QString helpmsg(tr("Input Status shows the current information "
772 "about the state of backend inputs"));
773 if (m_helpText)
774 m_helpText->SetText(helpmsg);
775 if (m_justHelpText)
776 m_justHelpText->SetText(helpmsg);
777
779 query.prepare(
780 "SELECT cardid, displayname "
781 "FROM capturecard ORDER BY displayname, cardid");
782
783 if (!query.exec() || !query.isActive())
784 {
785 MythDB::DBError("StatusBox::doTunerStatus()", query);
786 return;
787 }
788
789 while (query.next())
790 {
791 int inputid = query.value(0).toInt();
792 QString inputname = query.value(1).toString();
793 if (!info.contains(inputname))
794 inputnames.append(inputname);
795
796 QString cmd = QString("QUERY_REMOTEENCODER %1").arg(inputid);
797 QStringList strlist( cmd );
798 strlist << "GET_STATE";
799
801 int state = strlist[0].toInt();
802
803 if (state == kState_Error)
804 {
805 strlist.clear();
806 strlist << QString("QUERY_REMOTEENCODER %1").arg(inputid);
807 strlist << "GET_SLEEPSTATUS";
808
810 int sleepState = strlist[0].toInt();
811
812 if (sleepState == -1)
813 info[inputname].m_errored += 1;
814 else if (sleepState == sStatus_Undefined)
815 info[inputname].m_unavailable += 1;
816 else
817 info[inputname].m_sleeping += 1;
818 }
819 else if (state == kState_RecordingOnly ||
821 {
822 info[inputname].m_recording += 1;
823 }
824 else if (state == kState_WatchingLiveTV)
825 {
826 info[inputname].m_livetv += 1;
827 }
828 else
829 {
830 info[inputname].m_available += 1;
831 }
832
833 if (state == kState_RecordingOnly ||
834 state == kState_WatchingRecording ||
835 state == kState_WatchingLiveTV)
836 {
837 strlist = QStringList( QString("QUERY_RECORDER %1").arg(inputid));
838 strlist << "GET_RECORDING";
840 ProgramInfo pginfo(strlist);
841 if (pginfo.GetChanID())
842 {
843 QString titlesub = pginfo.GetTitle();
844 if (!pginfo.GetSubtitle().isEmpty())
845 titlesub += QString(" - ") + pginfo.GetSubtitle();
846 info[inputname].m_recordings += titlesub;
847 }
848 }
849 }
850
851 for (const QString& inputname : std::as_const(inputnames))
852 {
853 QStringList statuslist;
854 if (info[inputname].m_errored)
855 statuslist << tr("%1 errored").arg(info[inputname].m_errored);
856 if (info[inputname].m_unavailable)
857 statuslist << tr("%1 unavailable").arg(info[inputname].m_unavailable);
858 if (info[inputname].m_sleeping)
859 statuslist << tr("%1 sleeping").arg(info[inputname].m_sleeping);
860 if (info[inputname].m_recording)
861 statuslist << tr("%1 recording").arg(info[inputname].m_recording);
862 if (info[inputname].m_livetv)
863 statuslist << tr("%1 live television").arg(info[inputname].m_livetv);
864 if (info[inputname].m_available)
865 statuslist << tr("%1 available").arg(info[inputname].m_available);
866
867 QString fontstate;
868 if (info[inputname].m_errored)
869 fontstate = "error";
870 else if (info[inputname].m_unavailable || info[inputname].m_sleeping)
871 fontstate = "warning";
872
873 QString shortstatus = tr("Input %1: %2")
874 .arg(inputname, statuslist.join(tr(", ")));
875 QString longstatus = shortstatus + "\n" +
876 info[inputname].m_recordings.join("\n");
877
878 AddLogLine(shortstatus, helpmsg, longstatus, longstatus, fontstate);
879 }
880}
881
883{
884 if (m_iconState)
886 m_logList->Reset();
887
888 QString helpmsg(tr("Log Entries shows any unread log entries "
889 "from the system if you have logging enabled"));
890 if (m_helpText)
891 m_helpText->SetText(helpmsg);
892 if (m_justHelpText)
893 m_justHelpText->SetText(helpmsg);
894
896 query.prepare("SELECT logid, module, priority, logdate, host, "
897 "message, details "
898 "FROM mythlog WHERE acknowledged = 0 "
899 "AND priority <= :PRIORITY ORDER BY logdate DESC;");
900 query.bindValue(":PRIORITY", m_minLevel);
901
902 if (query.exec())
903 {
904 QString line;
905 QString detail;
906 while (query.next())
907 {
908 line = QString("%1").arg(query.value(5).toString());
909
910 detail = tr("On %1 from %2.%3\n%4\n")
912 MythDate::as_utc(query.value(3).toDateTime()),
914 query.value(4).toString(),
915 query.value(1).toString(),
916 query.value(5).toString());
917
918 QString tmp = query.value(6).toString();
919 if (!tmp.isEmpty())
920 detail.append(tmp);
921 else
922 detail.append(tr("No further details"));
923
924 AddLogLine(line, helpmsg, detail, detail,
925 "", query.value(0).toString());
926 }
927
928 if (query.size() == 0)
929 {
930 AddLogLine(tr("No items found at priority level %1 or lower.")
931 .arg(m_minLevel), helpmsg);
932 AddLogLine(tr("Use 1-8 to change priority level."), helpmsg);
933 }
934 }
935}
936
938{
939 if (m_iconState)
940 m_iconState->DisplayState("jobqueue");
941 m_logList->Reset();
942
943 QString helpmsg(tr("Job Queue shows any jobs currently in "
944 "MythTV's Job Queue such as a commercial "
945 "detection job."));
946 if (m_helpText)
947 m_helpText->SetText(helpmsg);
948 if (m_justHelpText)
949 m_justHelpText->SetText(helpmsg);
950
951 QMap<int, JobQueueEntry> jobs;
952 QMap<int, JobQueueEntry>::Iterator it;
953
957
958 if (!jobs.empty())
959 {
960 QString detail;
961 QString line;
962
963 for (it = jobs.begin(); it != jobs.end(); ++it)
964 {
965 ProgramInfo pginfo((*it).chanid, (*it).recstartts);
966
967 if (!pginfo.GetChanID())
968 continue;
969
970 detail = QString("%1\n%2 %3 @ %4\n%5 %6 %7 %8")
971 .arg(pginfo.GetTitle(),
972 pginfo.GetChannelName(),
973 pginfo.GetChanNum(),
975 pginfo.GetRecordingStartTime(),
977 tr("Job:"),
978 JobQueue::JobText((*it).type),
979 tr("Status: "),
980 JobQueue::StatusText((*it).status));
981
982 if ((*it).status != JOB_QUEUED)
983 detail += " (" + (*it).hostname + ')';
984
985 if ((*it).schedruntime > MythDate::current())
986 {
987 detail += '\n' + tr("Scheduled Run Time:") + ' ' +
989 (*it).schedruntime,
991 }
992 else
993 {
994 detail += '\n' + (*it).comment;
995 }
996
997 line = QString("%1 @ %2")
998 .arg(pginfo.GetTitle(),
1000 pginfo.GetRecordingStartTime(),
1002
1003 QString font;
1004 if ((*it).status == JOB_ERRORED)
1005 font = "error";
1006 else if ((*it).status == JOB_ABORTED)
1007 font = "warning";
1008
1009 AddLogLine(line, helpmsg, detail, detail, font,
1010 QString("%1").arg((*it).id));
1011 }
1012 }
1013 else
1014 {
1015 AddLogLine(tr("Job Queue is currently empty."), helpmsg);
1016 }
1017
1018}
1019
1020// Some helper routines for doMachineStatus() that format the output strings
1021
1022static QString usage_str_kb(long long total,
1023 long long used,
1024 long long free)
1025{
1026 QString ret = QObject::tr("Unknown");
1027 if (total > 0.0 && free > 0.0)
1028 {
1029 double percent = (100.0*free)/total;
1030 ret = StatusBox::tr("%1 total, %2 used, %3 (or %4%) free.")
1031 .arg(StringUtil::formatKBytes(total),
1034 .arg(percent, 0, 'f', (percent >= 10.0) ? 0 : 2);
1035 }
1036 return ret;
1037}
1038
1039static QString usage_str_mb(float total, float used, float free)
1040{
1041 return usage_str_kb((long long)(total*1024), (long long)(used*1024),
1042 (long long)(free*1024));
1043}
1044
1045static void disk_usage_with_rec_time_kb(QStringList& out, long long total,
1046 long long used, long long free,
1047 const recprof2bps_t& prof2bps)
1048{
1049 const QString tail = StatusBox::tr(", using your %1 rate of %2 kb/s");
1050
1051 out<<usage_str_kb(total, used, free);
1052 if (free<0)
1053 return;
1054
1055 // NOLINTNEXTLINE(modernize-loop-convert)
1056 for (auto it = prof2bps.begin(); it != prof2bps.end(); ++it)
1057 {
1058 const QString pro =
1059 tail.arg(it.key()).arg((int)((float)(*it) / 1024.0F));
1060
1061 long long bytesPerMin = ((*it) >> 1) * 15LL;
1062 uint minLeft = ((free<<5)/bytesPerMin)<<5;
1063 minLeft = (minLeft/15)*15;
1064 uint hoursLeft = minLeft/60;
1065 QString hourstring = StatusBox::tr("%n hour(s)", "", hoursLeft);
1066 QString minstring = StatusBox::tr("%n minute(s)", "", minLeft%60);
1067 QString remainstring = StatusBox::tr("%1 remaining", "time");
1068 if (minLeft%60 == 0)
1069 out<<remainstring.arg(hourstring) + pro;
1070 else if (minLeft > 60)
1071 {
1072 out<<StatusBox::tr("%1 and %2 remaining", "time")
1073 .arg(hourstring, minstring) + pro;
1074 }
1075 else
1076 {
1077 out<<remainstring.arg(minstring) + pro;
1078 }
1079 }
1080}
1081
1082static QString uptimeStr(std::chrono::seconds uptime)
1083{
1084 QString str = " " + StatusBox::tr("Uptime") + ": ";
1085
1086 if (uptime == 0s)
1087 return str + StatusBox::tr("unknown", "unknown uptime");
1088
1089 auto days = duration_cast<std::chrono::days>(uptime);
1090 auto secs = uptime % 24h;
1091
1092 QString astext;
1093 if (days.count() > 0)
1094 {
1095 astext = QString("%1, %2")
1096 .arg(StatusBox::tr("%n day(s)", "", days.count()),
1097 MythDate::formatTime(secs, "H:mm"));
1098 } else {
1099 astext = MythDate::formatTime(secs, "H:mm:ss");
1100 }
1101 return str + astext;
1102}
1103
1107void StatusBox::getActualRecordedBPS(const QString& hostnames)
1108{
1109 m_recordingProfilesBps.clear();
1110
1111 QString querystr;
1113
1114 querystr =
1115 "SELECT sum(filesize) * 8 / "
1116 "sum(((unix_timestamp(endtime) - unix_timestamp(starttime)))) "
1117 "AS avg_bitrate "
1118 "FROM recorded WHERE hostname in (%1) "
1119 "AND (unix_timestamp(endtime) - unix_timestamp(starttime)) > 300;";
1120
1121 query.prepare(querystr.arg(hostnames));
1122
1123 if (query.exec() && query.next() &&
1124 query.value(0).toDouble() > 0)
1125 {
1126 QString rateStr = tr("average", "average rate");
1127
1128 // Don't user a tr() directly here as the Qt tools will
1129 // not be able to extract the string for translation.
1130 m_recordingProfilesBps[rateStr] =
1131 (int)(query.value(0).toDouble());
1132 }
1133
1134 querystr =
1135 "SELECT max(filesize * 8 / "
1136 "(unix_timestamp(endtime) - unix_timestamp(starttime))) "
1137 "AS max_bitrate "
1138 "FROM recorded WHERE hostname in (%1) "
1139 "AND (unix_timestamp(endtime) - unix_timestamp(starttime)) > 300;";
1140
1141 query.prepare(querystr.arg(hostnames));
1142
1143 if (query.exec() && query.next() &&
1144 query.value(0).toDouble() > 0)
1145 {
1146 QString rateStr = tr("maximum", "maximum rate");
1147
1148 // Don't user a tr() directly here as the Qt tools will
1149 // not be able to extract the string for translation.
1150 m_recordingProfilesBps[rateStr] =
1151 (int)(query.value(0).toDouble());
1152 }
1153}
1154
1164{
1165 if (m_iconState)
1166 m_iconState->DisplayState("machine");
1167 m_logList->Reset();
1168 QString machineStr = tr("Machine Status shows some operating system "
1169 "statistics of this machine and the MythTV "
1170 "server.");
1171
1172 if (m_helpText)
1173 m_helpText->SetText(machineStr);
1174 if (m_justHelpText)
1175 m_justHelpText->SetText(machineStr);
1176
1177 QString line;
1179 line = tr("System:");
1180 else
1181 line = tr("This machine:");
1182 AddLogLine(line, machineStr);
1183
1184 // Time
1185 StatusBoxItem *timebox = AddLogLine("");
1186 auto UpdateTime = [](StatusBoxItem* Item)
1187 {
1188 Item->SetText(" " + tr("System time") + ": " + QDateTime::currentDateTime().toString());
1189 };
1190 UpdateTime(timebox);
1191 connect(timebox, &StatusBoxItem::UpdateRequired, UpdateTime);
1192 timebox->Start();
1193
1194 // Hostname & IP
1195 AddLogLine(" " + tr("Hostname") + ": " + gCoreContext->GetHostName());
1196 AddLogLine(" " + tr("OS") + QString(": %1 (%2)").arg(QSysInfo::prettyProductName(),
1197 QSysInfo::currentCpuArchitecture()));
1198 AddLogLine(" " + tr("Qt version") + QString(": %1").arg(qVersion()));
1199
1200 QList allInterfaces = QNetworkInterface::allInterfaces();
1201 for (const QNetworkInterface & iface : std::as_const(allInterfaces))
1202 {
1203 QNetworkInterface::InterfaceFlags f = iface.flags();
1204 if (!(f & QNetworkInterface::IsUp))
1205 continue;
1206 if (!(f & QNetworkInterface::IsRunning))
1207 continue;
1208 if ((f & QNetworkInterface::IsLoopBack) != 0U)
1209 continue;
1210
1211 QNetworkInterface::InterfaceType type = iface.type();
1212 QString name = type == QNetworkInterface::Wifi ? tr("WiFi") : tr("Ethernet");
1213 AddLogLine(" " + name + QString(" (%1): ").arg(iface.humanReadableName()));
1214 AddLogLine(" " + tr("MAC Address") + ": " + iface.hardwareAddress());
1215 QList addresses = iface.addressEntries();
1216 for (const QNetworkAddressEntry & addr : std::as_const(addresses))
1217 {
1218 if (addr.ip().protocol() == QAbstractSocket::IPv4Protocol ||
1219 addr.ip().protocol() == QAbstractSocket::IPv6Protocol)
1220 {
1221 AddLogLine(" " + tr("IP Address") + ": " + addr.ip().toString());
1222 }
1223 }
1224 }
1225 AddLogLine(line, machineStr);
1226
1227 // uptime
1228 std::chrono::seconds uptime = 0s;
1229 if (getUptime(uptime))
1230 {
1231 auto UpdateUptime = [](StatusBoxItem* Item)
1232 {
1233 std::chrono::seconds time = 0s;
1234 if (getUptime(time))
1235 Item->SetText(uptimeStr(time));
1236 };
1237 StatusBoxItem *uptimeitem = AddLogLine(uptimeStr(uptime));
1238 connect(uptimeitem, &StatusBoxItem::UpdateRequired, UpdateUptime);
1239 uptimeitem->Start(1min);
1240 }
1241
1242 // weighted average loads
1243#if !defined(_WIN32) && !defined(Q_OS_ANDROID)
1244 auto UpdateLoad = [](StatusBoxItem* Item)
1245 {
1246 loadArray loads = getLoadAvgs();
1247 Item->SetText(QString(" %1: %2 %3 %4").arg(tr("Load")).arg(loads[0], 1, 'f', 2)
1248 .arg(loads[1], 1, 'f', 2).arg(loads[2], 1, 'f', 2));
1249 };
1250 StatusBoxItem* loaditem = AddLogLine("");
1251 UpdateLoad(loaditem);
1252 connect(loaditem, &StatusBoxItem::UpdateRequired, UpdateLoad);
1253 loaditem->Start();
1254#endif
1255
1256 // memory usage
1257 int totalM = 0; // Physical memory
1258 int freeM = 0;
1259 int totalS = 0; // Virtual memory (swap)
1260 int freeS = 0;
1261 if (getMemStats(totalM, freeM, totalS, freeS))
1262 {
1263 auto UpdateMem = [](StatusBoxItem* Item)
1264 {
1265 int totm = 0;
1266 int freem = 0;
1267 int tots = 0;
1268 int frees = 0;
1269 if (getMemStats(totm, freem, tots, frees))
1270 Item->SetText(QString(" " + tr("RAM") + ": " + usage_str_mb(totm, totm - freem, freem)));
1271 };
1272
1273 auto UpdateSwap = [](StatusBoxItem* Item)
1274 {
1275 int totm = 0;
1276 int freem = 0;
1277 int tots = 0;
1278 int frees = 0;
1279 if (getMemStats(totm, freem, tots, frees))
1280 Item->SetText(QString(" " + tr("Swap") + ": " + usage_str_mb(tots, tots - frees, frees)));
1281 };
1282 StatusBoxItem* mem = AddLogLine("", machineStr);
1283 StatusBoxItem* swap = AddLogLine("", machineStr);
1284 UpdateMem(mem);
1285 UpdateSwap(swap);
1286 connect(mem, &StatusBoxItem::UpdateRequired, UpdateMem);
1287 connect(swap, &StatusBoxItem::UpdateRequired, UpdateSwap);
1288 mem->Start(3s);
1289 swap->Start(3s);
1290 }
1291
1292 if (!m_isBackendActive)
1293 {
1294 line = tr("MythTV server") + ':';
1295 AddLogLine(line, machineStr);
1296
1297 // Hostname & IP
1298 line = " " + tr("Hostname") + ": " + gCoreContext->GetSetting("MasterServerName");
1299 line.append(", " + tr("IP") + ": " + gCoreContext->GetSetting("MasterServerIP"));
1300 AddLogLine(line, machineStr);
1301
1302 // uptime
1303 if (RemoteGetUptime(uptime))
1304 {
1305 auto UpdateRemoteUptime = [](StatusBoxItem* Item)
1306 {
1307 std::chrono::seconds time = 0s;
1308 RemoteGetUptime(time);
1309 Item->SetText(uptimeStr(time));
1310 };
1311 StatusBoxItem *remoteuptime = AddLogLine(uptimeStr(uptime));
1312 connect(remoteuptime, &StatusBoxItem::UpdateRequired, UpdateRemoteUptime);
1313 remoteuptime->Start(1min);
1314 }
1315
1316 // weighted average loads
1317 loadArray floads;
1318 if (RemoteGetLoad(floads))
1319 {
1320 auto UpdateRemoteLoad = [](StatusBoxItem* Item)
1321 {
1322 loadArray loads = { 0.0, 0.0, 0.0 };
1323 RemoteGetLoad(loads);
1324 Item->SetText(QString(" %1: %2 %3 %4").arg(tr("Load")).arg(loads[0], 1, 'f', 2)
1325 .arg(loads[1], 1, 'f', 2).arg(loads[2], 1, 'f', 2));
1326 };
1327 StatusBoxItem* remoteloaditem = AddLogLine("");
1328 UpdateRemoteLoad(remoteloaditem);
1329 connect(remoteloaditem, &StatusBoxItem::UpdateRequired, UpdateRemoteLoad);
1330 remoteloaditem->Start();
1331 }
1332
1333 // memory usage
1334 if (RemoteGetMemStats(totalM, freeM, totalS, freeS))
1335 {
1336 auto UpdateRemoteMem = [](StatusBoxItem* Item)
1337 {
1338 int totm = 0;
1339 int freem = 0;
1340 int tots = 0;
1341 int frees = 0;
1342 if (RemoteGetMemStats(totm, freem, tots, frees))
1343 Item->SetText(QString(" " + tr("RAM") + ": " + usage_str_mb(totm, totm - freem, freem)));
1344 };
1345
1346 auto UpdateRemoteSwap = [](StatusBoxItem* Item)
1347 {
1348 int totm = 0;
1349 int freem = 0;
1350 int tots = 0;
1351 int frees = 0;
1352 if (RemoteGetMemStats(totm, freem, tots, frees))
1353 Item->SetText(QString(" " + tr("Swap") + ": " + usage_str_mb(tots, tots - frees, frees)));
1354 };
1355 StatusBoxItem* rmem = AddLogLine("", machineStr);
1356 StatusBoxItem* rswap = AddLogLine("", machineStr);
1357 UpdateRemoteMem(rmem);
1358 UpdateRemoteSwap(rswap);
1359 connect(rmem, &StatusBoxItem::UpdateRequired, UpdateRemoteMem);
1360 connect(rswap, &StatusBoxItem::UpdateRequired, UpdateRemoteSwap);
1361 rmem->Start(10s);
1362 rswap->Start(11s);
1363 }
1364 }
1365
1366 // get free disk space
1367 QString hostnames;
1368
1370 for (int i = 0; i < fsInfos.size(); ++i)
1371 {
1372 // For a single-directory installation just display the totals
1373 if ((fsInfos.size() == 2) && (i == 0) &&
1374 (fsInfos[i].getPath() != "TotalDiskSpace") &&
1375 (fsInfos[i+1].getPath() == "TotalDiskSpace"))
1376 i++;
1377
1378 hostnames = QString("\"%1\"").arg(fsInfos[i].getHostname());
1379 hostnames.replace(' ', "");
1380 hostnames.replace(',', "\",\"");
1381
1382 getActualRecordedBPS(hostnames);
1383
1384 QStringList list;
1386 fsInfos[i].getTotalSpace(), fsInfos[i].getUsedSpace(),
1387 fsInfos[i].getTotalSpace() - fsInfos[i].getUsedSpace(),
1389
1390 if (fsInfos[i].getPath() == "TotalDiskSpace")
1391 {
1392 line = tr("Total Disk Space:");
1393 AddLogLine(line, machineStr);
1394 }
1395 else
1396 {
1397 line = tr("MythTV Drive #%1:").arg(fsInfos[i].getFSysID());
1398 AddLogLine(line, machineStr);
1399
1400 QStringList tokens = fsInfos[i].getPath().split(',');
1401
1402 if (tokens.size() > 1)
1403 {
1404 AddLogLine(QString(" ") + tr("Directories:"), machineStr);
1405
1406 int curToken = 0;
1407 while (curToken < tokens.size())
1408 AddLogLine(QString(" ") +
1409 tokens[curToken++], machineStr);
1410 }
1411 else
1412 {
1413 AddLogLine(QString(" " ) + tr("Directory:") + ' ' +
1414 fsInfos[i].getPath(), machineStr);
1415 }
1416 }
1417
1418 for (auto & diskinfo : list)
1419 {
1420 line = QString(" ") + diskinfo;
1421 AddLogLine(line, machineStr);
1422 }
1423 }
1424
1425}
1426
1428{
1429 if (m_iconState)
1430 m_iconState->DisplayState("decoders");
1431 m_logList->Reset();
1432 QString displayhelp = tr("Available hardware decoders for video playback.");
1433 if (m_helpText)
1434 m_helpText->SetText(displayhelp);
1435 if (m_justHelpText)
1436 m_justHelpText->SetText(displayhelp);
1437
1438 QStringList decoders = MythCodecContext::GetDecoderDescription();
1439 if (decoders.isEmpty())
1440 {
1441 AddLogLine(tr("None"));
1442 }
1443 else
1444 {
1445 for (const QString & decoder : std::as_const(decoders))
1446 AddLogLine(decoder);
1447 }
1448}
1449
1451{
1452 if (m_iconState)
1453 m_iconState->DisplayState("display");
1454 m_logList->Reset();
1455 auto displayhelp = tr("Display information.");
1456 if (m_helpText)
1457 m_helpText->SetText(displayhelp);
1458 if (m_justHelpText)
1459 m_justHelpText->SetText(displayhelp);
1460
1461 auto desc = GetMythMainWindow()->GetDisplay()->GetDescription();
1462 for (const auto & line : std::as_const(desc))
1463 AddLogLine(line);
1464}
1465
1467{
1468 if (m_iconState)
1469 m_iconState->DisplayState("render");
1470 m_logList->Reset();
1471 auto displayhelp = tr("Render information.");
1472 if (m_helpText)
1473 m_helpText->SetText(displayhelp);
1474 if (m_justHelpText)
1475 m_justHelpText->SetText(displayhelp);
1476
1477 auto * render = GetMythMainWindow()->GetRenderDevice();
1478 if (render && render->Type() == kRenderOpenGL)
1479 {
1480 auto * opengl = dynamic_cast<MythRenderOpenGL*>(render);
1481
1482 if (opengl)
1483 {
1484 auto UpdateFPS = [](StatusBoxItem* Item)
1485 {
1486 uint64_t swapcount = 0;
1487 auto * rend = GetMythMainWindow()->GetRenderDevice();
1488 if (auto * gl = dynamic_cast<MythRenderOpenGL*>(rend); gl != nullptr)
1489 swapcount = gl->GetSwapCount();
1490 Item->SetText(tr("Current fps\t: %1").arg(swapcount));
1491 };
1492
1493 auto * fps = AddLogLine("");
1494 // Reset the frame counter
1495 (void)opengl->GetSwapCount();
1496 UpdateFPS(fps);
1497 connect(fps, &StatusBoxItem::UpdateRequired, UpdateFPS);
1498 fps->Start();
1499 }
1500
1501 if (opengl && (opengl->GetExtraFeatures() & kGLNVMemory))
1502 {
1503 auto GetGPUMem = []()
1504 {
1505 auto * rend = GetMythMainWindow()->GetRenderDevice();
1506 if (auto * gl = dynamic_cast<MythRenderOpenGL*>(rend); gl != nullptr)
1507 return gl->GetGPUMemory();
1508 return std::tuple<int,int,int> { 0, 0, 0 };
1509 };
1510 auto UpdateUsed = [&GetGPUMem](StatusBoxItem* Item)
1511 {
1512 auto mem = GetGPUMem();
1513 int total = std::get<0>(mem);
1514 if (total > 0)
1515 {
1516 int avail = std::get<2>(mem);
1517 Item->SetText(tr("GPU memory used : %1MB").arg(total - avail));
1518 }
1519 };
1520
1521 auto UpdateFree = [&GetGPUMem](StatusBoxItem* Item)
1522 {
1523 auto mem = GetGPUMem();
1524 int total = std::get<0>(mem);
1525 if (total > 0)
1526 {
1527 int avail = std::get<2>(mem);
1528 int percent = static_cast<int>((avail / static_cast<float>(total) * 100.0F));
1529 Item->SetText(tr("GPU memory free : %1MB (or %2%)").arg(avail).arg(percent));
1530 }
1531 };
1532
1533 auto current = GetGPUMem();
1534 // Total and dedicated will not change
1535 AddLogLine(tr("GPU memory total : %1MB").arg(std::get<0>(current)));
1536 AddLogLine(tr("GPU memory dedicated: %1MB").arg(std::get<1>(current)));
1537 auto * used = AddLogLine("");
1538 auto * freemem = AddLogLine("");
1539 UpdateUsed(used);
1540 UpdateFree(freemem);
1541 connect(used, &StatusBoxItem::UpdateRequired, UpdateUsed);
1542 connect(freemem, &StatusBoxItem::UpdateRequired, UpdateFree);
1543 used->Start();
1544 freemem->Start();
1545 }
1546
1547 auto desc = render->GetDescription();
1548 for (const auto & line : std::as_const(desc))
1549 AddLogLine(line);
1550 }
1551}
1552
1556void StatusBox::doAutoExpireList(bool updateExpList)
1557{
1558 if (m_iconState)
1559 m_iconState->DisplayState("autoexpire");
1560 m_logList->Reset();
1561
1562 QString helpmsg(tr("The AutoExpire List shows all recordings "
1563 "which may be expired and the order of "
1564 "their expiration. Recordings at the top "
1565 "of the list will be expired first."));
1566 if (m_helpText)
1567 m_helpText->SetText(helpmsg);
1568 if (m_justHelpText)
1569 m_justHelpText->SetText(helpmsg);
1570
1571 QString contentLine;
1572 QString detailInfo;
1573 QString staticInfo;
1574 long long totalSize(0);
1575 long long liveTVSize(0);
1576 int liveTVCount(0);
1577 long long deletedGroupSize(0);
1578 int deletedGroupCount(0);
1579
1580 std::vector<ProgramInfo *>::iterator it;
1581
1582 if (updateExpList)
1583 {
1584 for (it = m_expList.begin(); it != m_expList.end(); ++it)
1585 delete *it;
1586 m_expList.clear();
1587
1589 }
1590
1591 for (it = m_expList.begin(); it != m_expList.end(); ++it)
1592 {
1593 ProgramInfo *pginfo = *it;
1594
1595 totalSize += pginfo->GetFilesize();
1596 if (pginfo->GetRecordingGroup() == "LiveTV")
1597 {
1598 liveTVSize += pginfo->GetFilesize();
1599 liveTVCount++;
1600 }
1601 else if (pginfo->GetRecordingGroup() == "Deleted")
1602 {
1603 deletedGroupSize += pginfo->GetFilesize();
1604 deletedGroupCount++;
1605 }
1606 }
1607
1608 staticInfo = tr("%n recording(s) consuming %1 (is) allowed to expire\n", "",
1609 m_expList.size()).arg(StringUtil::formatKBytes(totalSize / 1024));
1610
1611 if (liveTVCount)
1612 staticInfo += tr("%n (is) LiveTV and consume(s) %1\n", "", liveTVCount)
1613 .arg(StringUtil::formatKBytes(liveTVSize / 1024));
1614
1615 if (deletedGroupCount)
1616 {
1617 staticInfo += tr("%n (is) Deleted and consume(s) %1\n", "",
1618 deletedGroupCount)
1619 .arg(StringUtil::formatKBytes(deletedGroupSize / 1024));
1620 }
1621
1622 for (it = m_expList.begin(); it != m_expList.end(); ++it)
1623 {
1624 ProgramInfo *pginfo = *it;
1625 QDateTime starttime = pginfo->GetRecordingStartTime();
1626 QDateTime endtime = pginfo->GetRecordingEndTime();
1627 contentLine =
1629 starttime, MythDate::kDateFull | MythDate::kSimplify) + " - ";
1630
1631 contentLine +=
1632 "(" + ProgramInfo::i18n(pginfo->GetRecordingGroup()) + ") ";
1633
1634 contentLine += pginfo->GetTitle() +
1635 " (" + StringUtil::formatKBytes(pginfo->GetFilesize() / 1024) + ")";
1636
1637 detailInfo =
1640 " - " +
1643
1644 detailInfo += " (" + StringUtil::formatKBytes(pginfo->GetFilesize() / 1024) + ")";
1645
1646 detailInfo += " (" + ProgramInfo::i18n(pginfo->GetRecordingGroup()) + ")";
1647
1648 detailInfo += "\n" + pginfo->toString(ProgramInfo::kTitleSubtitle, " - ");
1649
1650 AddLogLine(contentLine, staticInfo, detailInfo,
1651 staticInfo + detailInfo);
1652 }
1653}
1654
1656
1657/* vim: set expandtab tabstop=4 shiftwidth=4: */
size_t size(void) const
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
static const Type kEventType
Definition: mythdialogbox.h:56
static int GetJobsInQueue(QMap< int, JobQueueEntry > &jobs, int findJobs=JOB_LIST_NOT_DONE)
Definition: jobqueue.cpp:1282
static QString JobText(int jobType)
Definition: jobqueue.cpp:1112
static bool DeleteJob(int jobID)
Definition: jobqueue.cpp:872
static bool StopJob(int jobID)
Definition: jobqueue.cpp:742
static bool ResumeJob(int jobID)
Definition: jobqueue.cpp:724
static bool ChangeJobStatus(int jobID, int newStatus, const QString &comment="")
Definition: jobqueue.cpp:983
static enum JobStatus GetJobStatus(int jobID)
Definition: jobqueue.cpp:1528
static bool PauseJob(int jobID)
Definition: jobqueue.cpp:715
static QString StatusText(int status)
Definition: jobqueue.cpp:1135
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
QVariant value(int i) const
Definition: mythdbcon.h:204
int size(void) const
Definition: mythdbcon.h:214
bool isActive(void) const
Definition: mythdbcon.h:215
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
static QStringList GetDecoderDescription(void)
Dialog asking for user confirmation.
QString GetHostName(void)
void SaveSetting(const QString &key, int newValue)
QString GetSetting(const QString &key, const QString &defaultval="")
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
int GetNumSetting(const QString &key, int defaultval=0)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
Basic menu dialog, message and a list of options.
QStringList GetDescription()
MythDisplay * GetDisplay()
MythRender * GetRenderDevice()
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)
Screen in which all other widgets are contained and rendered.
void BuildFocusList(void)
MythUIType * GetFocusWidget(void) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
QString GetText(const QString &name="") const
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
MythUIButtonListItem * GetItemCurrent() const
void SetItemCurrent(MythUIButtonListItem *item)
void RemoveItem(MythUIButtonListItem *item)
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
int GetTopItemPos(void) const
int GetCurrentPos() const
void itemClicked(MythUIButtonListItem *item)
void itemSelected(MythUIButtonListItem *item)
This widget is used for grouping other widgets for display when a particular named state is called.
bool DisplayState(const QString &name)
All purpose text widget, displays a text string.
Definition: mythuitext.h:29
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:138
Holds information on recordings and videos.
Definition: programinfo.h:70
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:375
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
QString GetRecordingGroup(void) const
Definition: programinfo.h:422
QString GetChannelName(void) const
This is the channel name in the local market, i.e.
Definition: programinfo.h:389
QString GetTitle(void) const
Definition: programinfo.h:364
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:407
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:379
static QString i18n(const QString &msg)
Translations for play,recording, & storage groups +.
virtual uint64_t GetFilesize(void) const
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:415
QString GetSubtitle(void) const
Definition: programinfo.h:366
static QString toString(RecStatus::Type recstatus, uint id)
Converts "recstatus" into a short (unreadable) string.
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:36
void ApplyRecordRecGroupChange(const QString &newrecgroup)
Sets the recording group, both in this RecordingInfo and in the database.
void UpdateRequired(StatusBoxItem *Item)
void Start(std::chrono::seconds Interval=1s)
Definition: statusbox.cpp:42
void doJobQueueStatus()
Definition: statusbox.cpp:937
StatusBox(MythScreenStack *parent)
Definition: statusbox.cpp:57
void doScheduleStatus()
Definition: statusbox.cpp:547
void getActualRecordedBPS(const QString &hostnames)
Fills in m_recordingProfilesBps w/ average bitrate from recorded table.
Definition: statusbox.cpp:1107
void clicked(MythUIButtonListItem *item)
Definition: statusbox.cpp:250
void customEvent(QEvent *event) override
Definition: statusbox.cpp:356
bool m_isBackendActive
Definition: statusbox.h:95
StatusBoxItem * AddLogLine(const QString &line, const QString &help="", const QString &detail="", const QString &helpdetail="", const QString &state="", const QString &data="")
Definition: statusbox.cpp:151
void doTunerStatus()
Definition: statusbox.cpp:752
MythUIButtonList * m_categoryList
Definition: statusbox.h:83
void setHelpText(MythUIButtonListItem *item)
Definition: statusbox.cpp:217
~StatusBox(void) override
Definition: statusbox.cpp:72
void doAutoExpireList()
Show list of recordings which may AutoExpire.
Definition: statusbox.h:66
void doRenderStatus()
Definition: statusbox.cpp:1466
bool Create(void) override
Definition: statusbox.cpp:79
std::vector< ProgramInfo * > m_expList
Definition: statusbox.h:89
MythUIText * m_justHelpText
Definition: statusbox.h:82
MythUIButtonList * m_logList
Definition: statusbox.h:84
recprof2bps_t m_recordingProfilesBps
Definition: statusbox.h:87
void doLogEntries()
Definition: statusbox.cpp:882
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: statusbox.cpp:189
MythUIText * m_helpText
Definition: statusbox.h:81
void doMachineStatus()
Show machine status.
Definition: statusbox.cpp:1163
int m_minLevel
Definition: statusbox.h:93
MythUIStateType * m_iconState
Definition: statusbox.h:85
void updateLog()
MythScreenStack * m_popupStack
Definition: statusbox.h:91
void doDisplayStatus()
Definition: statusbox.cpp:1450
void doDecoderStatus()
Definition: statusbox.cpp:1427
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
Definition: statusbox.cpp:109
void doListingsStatus()
Definition: statusbox.cpp:452
void updateLogList(MythUIButtonListItem *item)
Definition: statusbox.cpp:229
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
unsigned int uint
Definition: compat.h:68
QVector< FileSystemInfo > FileSystemInfoList
static guint32 * tmp
Definition: goom_core.cpp:26
@ JOB_LIST_RECENT
Definition: jobqueue.h:71
@ JOB_LIST_NOT_DONE
Definition: jobqueue.h:69
@ JOB_LIST_ERROR
Definition: jobqueue.h:70
Q_DECLARE_METATYPE(std::chrono::seconds)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
bool RemoteGetUptime(std::chrono::seconds &uptime)
bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
Returns memory statistics in megabytes.
loadArray getLoadAvgs(void)
Returns the system load averages.
bool RemoteGetLoad(loadArray &load)
bool getUptime(std::chrono::seconds &uptime)
Returns uptime statistics.
bool RemoteGetMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
std::array< double, 3 > loadArray
Definition: mythmiscutil.h:22
@ kRenderOpenGL
@ kGLNVMemory
void(QObject::*)(void) const MythUICallbackMFc
Definition: mythuitype.h:45
void(QObject::*)(void) MythUICallbackMF
Definition: mythuitype.h:44
const char * GetMythSourceVersion()
Definition: mythversion.cpp:7
const char * GetMythSourcePath()
Definition: mythversion.cpp:12
MBASE_PUBLIC FileSystemInfoList GetInfoList(MythSocket *sock=nullptr)
QString formatTime(std::chrono::milliseconds msecs, QString fmt)
Format a milliseconds time value.
Definition: mythdate.cpp:242
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
Definition: mythdate.cpp:28
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
@ kSimplify
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:26
@ kDateFull
Default local time.
Definition: mythdate.h:19
@ kDateTimeShort
Default local time.
Definition: mythdate.h:24
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
MBASE_PUBLIC QString formatKBytes(int64_t sizeKB, int prec=1)
Definition: stringutil.cpp:357
dictionary info
Definition: azlyrics.py:7
duration< CHRONO_TYPE, ratio< 86400 > > days
Definition: mythchrono.h:25
bool LoadFromScheduler(AutoDeleteDeque< TYPE * > &destination, bool &hasConflicts, const QString &altTable="", int recordid=-1)
Definition: programinfo.h:939
bool RemoteDeleteRecording(uint recordingID, bool forceMetadataDelete, bool forgetHistory)
void RemoteGetAllExpiringRecordings(std::vector< ProgramInfo * > &expiringlist)
bool RemoteUndeleteRecording(uint recordingID)
@ kDisableAutoExpire
Definition: programtypes.h:193
@ kNoSearch
@ kTemplateRecord
static QString uptimeStr(std::chrono::seconds uptime)
Definition: statusbox.cpp:1082
static QString usage_str_kb(long long total, long long used, long long free)
Definition: statusbox.cpp:1022
#define ADD_STATUS_LOG_LINE(rtype, fstate)
static void disk_usage_with_rec_time_kb(QStringList &out, long long total, long long used, long long free, const recprof2bps_t &prof2bps)
Definition: statusbox.cpp:1045
static QString usage_str_mb(float total, float used, float free)
Definition: statusbox.cpp:1039
QMap< QString, unsigned int > recprof2bps_t
Definition: statusbox.h:21
QString m_help
Definition: statusbox.cpp:36
QString m_data
Definition: statusbox.cpp:38
QString m_line
Definition: statusbox.cpp:34
QString m_helpdetail
Definition: statusbox.cpp:37
QString m_state
Definition: statusbox.cpp:39
QString m_detail
Definition: statusbox.cpp:35
@ sStatus_Undefined
A slave's sleep status is undefined when it has never connected to the master backend or is not able ...
Definition: tv.h:120
@ kState_RecordingOnly
Recording Only is a TVRec only state for when we are recording a program, but there is no one current...
Definition: tv.h:87
@ kState_WatchingLiveTV
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
Definition: tv.h:66
@ kState_Error
Error State, if we ever try to enter this state errored is set.
Definition: tv.h:57
@ kState_WatchingRecording
Watching Recording is the state for when we are watching an in progress recording,...
Definition: tv.h:83