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