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