MythTV  master
progdetails.cpp
Go to the documentation of this file.
1 
2 // Qt
3 #include <QFile>
4 #include <QKeyEvent>
5 #include <QTextStream>
6 
7 // MythTV
9 #include "libmythbase/mythdate.h"
10 #include "libmythbase/mythdb.h"
14 #include "libmythui/mythuihelper.h"
15 
16 // MythFrontend
17 #include "progdetails.h"
18 
20 {
21  // Load the theme for this screen
22  bool foundtheme = LoadWindowFromXML("schedule-ui.xml", "programdetails", this);
23  if (!foundtheme)
24  return false;
25 
26  // Initialise details list
27  if (!m_infoList.Create(true))
28  {
29  LOG(VB_GENERAL, LOG_ERR, "Cannot load 'Info buttonlist'");
30  return false;
31  }
32 
34 
35  return true;
36 }
37 
38 QString ProgDetails::getRatings(bool recorded, uint chanid, const QDateTime& startts)
39 {
40  QString table = (recorded) ? "recordedrating" : "programrating";
41  QString sel = QString(
42  "SELECT `system`, rating FROM %1 "
43  "WHERE chanid = :CHANID "
44  "AND starttime = :STARTTIME").arg(table);
45 
47  query.prepare(sel);
48  query.bindValue(":CHANID", chanid);
49  query.bindValue(":STARTTIME", startts);
50 
51  if (!query.exec() || !query.isActive())
52  {
53  MythDB::DBError("ProgDetails::getRatings", query);
54  return "";
55  }
56 
57  QMap<QString,QString> main_ratings;
58  QString advisory;
59  while (query.next())
60  {
61  if (query.value(0).toString().toLower() == "advisory")
62  {
63  advisory += query.value(1).toString() + ", ";
64  continue;
65  }
66  main_ratings[query.value(0).toString()] = query.value(1).toString();
67  }
68 
69  advisory = advisory.left(advisory.length() - 2);
70 
71  if (main_ratings.empty())
72  return advisory;
73 
74  if (!advisory.isEmpty())
75  advisory = ": " + advisory;
76 
77  if (main_ratings.size() == 1)
78  {
79  return *main_ratings.begin() + advisory;
80  }
81 
82  QString ratings;
83  QMap<QString,QString>::const_iterator it;
84  for (it = main_ratings.cbegin(); it != main_ratings.cend(); ++it)
85  {
86  ratings += it.key() + ": " + *it + ", ";
87  }
88 
89  return ratings + "Advisory" + advisory;
90 }
91 
93 {
94  m_infoList.Hide();
95 }
96 
98 {
99  updatePage();
100 }
101 
103 {
104  if (m_data.isEmpty())
105  loadPage();
106 
108 }
109 
110 void ProgDetails::addItem(const QString &title, const QString &value,
112 {
113  if (value.isEmpty())
114  return;
115  ProgInfoList::DataItem item = std::make_tuple(title, value, level);
116  m_data.append(item);
117 }
118 
119 bool ProgDetails::keyPressEvent(QKeyEvent *event)
120 {
121  QStringList actions;
122  bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
123 
124  for (int i = 0; i < actions.size() && !handled; ++i)
125  {
126  QString action = actions[i];
127  handled = true;
128 
129  if (action == "INFO" || action == "SELECT")
130  {
131  m_infoList.Toggle();
132  updatePage();
133  }
134  else if (action == "DOWN")
135  {
137  }
138  else if (action == "UP")
139  {
140  m_infoList.PageUp();
141  }
142  else
143  handled = false;
144  }
145 
146  if (!handled && MythScreenType::keyPressEvent(event))
147  handled = true;
148 
149  return handled;
150 }
151 
152 void ProgDetails::PowerPriorities(const QString & ptable)
153 {
154  int recordid = m_progInfo.GetRecordingRuleID();
155 
156  // If not a scheduled recording, abort .... ?
157  if (!recordid)
158  return;
159 
160  using string_pair = QPair<QString, QString>;
161  QVector<string_pair> tests;
162  QString recmatch;
163  QString pwrpri;
164  QString desc;
165  QString adjustmsg;
166  int total = 0;
167 
168  MSqlQuery query(MSqlQuery::InitCon());
169 
170  int prefinputpri = gCoreContext->GetNumSetting("PrefInputPriority", 2);
171  int hdtvpriority = gCoreContext->GetNumSetting("HDTVRecPriority", 0);
172  int wspriority = gCoreContext->GetNumSetting("WSRecPriority", 0);
173  int slpriority = gCoreContext->GetNumSetting("SignLangRecPriority", 0);
174  int onscrpriority = gCoreContext->GetNumSetting("OnScrSubRecPriority", 0);
175  int ccpriority = gCoreContext->GetNumSetting("CCRecPriority", 0);
176  int hhpriority = gCoreContext->GetNumSetting("HardHearRecPriority", 0);
177  int adpriority = gCoreContext->GetNumSetting("AudioDescRecPriority", 0);
178 
179  tests.append(qMakePair(QString("channel.recpriority"),
180  QString("channel.recpriority")));
181  tests.append(qMakePair(QString("capturecard.recpriority"),
182  QString("capturecard.recpriority")));
183 
184  if (prefinputpri)
185  {
186  pwrpri = QString("(capturecard.cardid = record.prefinput) * %1")
187  .arg(prefinputpri);
188  tests.append(qMakePair(pwrpri, pwrpri));
189  }
190  if (hdtvpriority)
191  {
192  pwrpri = QString("(program.hdtv > 0 OR "
193  "FIND_IN_SET('HDTV', program.videoprop) > 0) * %1")
194  .arg(hdtvpriority);
195  tests.append(qMakePair(pwrpri, pwrpri));
196  }
197  if (wspriority)
198  {
199  pwrpri = QString
200  ("(FIND_IN_SET('WIDESCREEN', program.videoprop) > 0) * %1")
201  .arg(wspriority);
202  tests.append(qMakePair(pwrpri, pwrpri));
203  }
204  if (slpriority)
205  {
206  pwrpri = QString
207  ("(FIND_IN_SET('SIGNED', program.subtitletypes) > 0) * %1")
208  .arg(slpriority);
209  tests.append(qMakePair(pwrpri, pwrpri));
210  }
211  if (onscrpriority)
212  {
213  pwrpri = QString
214  ("(FIND_IN_SET('ONSCREEN', program.subtitletypes) > 0) * %1")
215  .arg(onscrpriority);
216  tests.append(qMakePair(pwrpri, pwrpri));
217  }
218  if (ccpriority)
219  {
220  pwrpri = QString
221  ("(FIND_IN_SET('NORMAL', program.subtitletypes) > 0 OR "
222  "program.closecaptioned > 0 OR program.subtitled > 0) * %1")
223  .arg(ccpriority);
224  tests.append(qMakePair(pwrpri, pwrpri));
225  }
226  if (hhpriority)
227  {
228  pwrpri = QString
229  ("(FIND_IN_SET('HARDHEAR', program.subtitletypes) > 0 OR "
230  "FIND_IN_SET('HARDHEAR', program.audioprop) > 0) * %1")
231  .arg(hhpriority);
232  tests.append(qMakePair(pwrpri, pwrpri));
233  }
234  if (adpriority)
235  {
236  pwrpri = QString
237  ("(FIND_IN_SET('VISUALIMPAIR', program.audioprop) > 0) * %1")
238  .arg(adpriority);
239  tests.append(qMakePair(pwrpri, pwrpri));
240  }
241 
242  query.prepare("SELECT recpriority, selectclause FROM powerpriority;");
243 
244  if (!query.exec())
245  {
246  MythDB::DBError("Power Priority", query);
247  return;
248  }
249 
250  while (query.next())
251  {
252  int adj = query.value(0).toInt();
253  if (adj)
254  {
255  QString sclause = query.value(1).toString();
256  sclause.remove(RecordingInfo::kReLeadingAnd);
257  sclause.remove(';');
258  pwrpri = QString("(%1) * %2").arg(sclause)
259  .arg(query.value(0).toInt());
260  pwrpri.replace("RECTABLE", "record");
261 
262  desc = pwrpri;
263  pwrpri += QString(" AS powerpriority ");
264 
265  tests.append(qMakePair(desc, pwrpri));
266  }
267  }
268 
269  recmatch = QString("INNER JOIN record "
270  " ON ( record.recordid = %1 ) ")
271  .arg(recordid);
272 
273  for (const auto & [label, csqlStart] : qAsConst(tests))
274  {
275  QString sqlStart = csqlStart;
276  query.prepare("SELECT " + sqlStart.replace("program.", "p.")
277  + QString
278  (" FROM %1 as p "
279  "INNER JOIN channel "
280  " ON ( channel.chanid = p.chanid ) "
281  "INNER JOIN capturecard "
282  " ON ( channel.sourceid = capturecard.sourceid AND "
283  " ( capturecard.schedorder <> 0 OR "
284  " capturecard.parentid = 0 ) ) ").arg(ptable)
285  + recmatch +
286  "WHERE p.chanid = :CHANID AND"
287  " p.starttime = :STARTTIME ;");
288 
289  query.bindValue(":CHANID", m_progInfo.GetChanID());
290  query.bindValue(":STARTTIME", m_progInfo.GetScheduledStartTime());
291 
292  adjustmsg = QString("%1 : ").arg(label);
293  if (query.exec() && query.next())
294  {
295  int adj = query.value(0).toInt();
296  if (adj)
297  {
298  adjustmsg += tr(" MATCHED, adding %1").arg(adj);
299  total += adj;
300  }
301  else
302  adjustmsg += tr(" not matched");
303  }
304  else
305  adjustmsg += tr(" Query FAILED");
306 
307  addItem(tr("Recording Priority Adjustment"), adjustmsg,
309  }
310 
311  if (!tests.isEmpty())
312  addItem(tr("Priority Adjustment Total"), QString::number(total),
314 }
315 
317 {
318  MSqlQuery query(MSqlQuery::InitCon());
319  QString category_type;
320  QString showtype;
321  QString year;
322  QString syndicatedEpisodeNum;
323  QString rating;
324  QString colorcode;
325  QString title_pronounce;
326  float stars = 0.0;
327  int partnumber = 0;
328  int parttotal = 0;
329  int audioprop = 0;
330  int videoprop = 0;
331  int subtype = 0;
332  int generic = 0;
333  bool recorded = false;
334 
335  RecordingRule* record = nullptr;
337  {
338  record = new RecordingRule();
339  record->LoadByProgram(&m_progInfo);
340  }
341 
342  if (m_progInfo.GetFilesize())
343  recorded = true;
344 
345  QString ptable = recorded ? "recordedprogram" : "program";
346 
348  {
349  query.prepare(QString("SELECT category_type, airdate, stars,"
350  " partnumber, parttotal, audioprop+0, videoprop+0,"
351  " subtitletypes+0, syndicatedepisodenumber, generic,"
352  " showtype, colorcode, title_pronounce"
353  " FROM %1 WHERE chanid = :CHANID AND"
354  " starttime = :STARTTIME ;").arg(ptable));
355 
356  query.bindValue(":CHANID", m_progInfo.GetChanID());
357  query.bindValue(":STARTTIME", m_progInfo.GetScheduledStartTime());
358 
359  if (query.exec() && query.next())
360  {
361  category_type = query.value(0).toString();
362  year = query.value(1).toString();
363  stars = query.value(2).toFloat();
364  partnumber = query.value(3).toInt();
365  parttotal = query.value(4).toInt();
366  audioprop = query.value(5).toInt();
367  videoprop = query.value(6).toInt();
368  subtype = query.value(7).toInt();
369  syndicatedEpisodeNum = query.value(8).toString();
370  generic = query.value(9).toInt();
371  showtype = query.value(10).toString();
372  colorcode = query.value(11).toString();
373  title_pronounce = query.value(12).toString();
374  }
375  else if (!query.isActive())
376  MythDB::DBError("ProgDetails", query);
377 
378  rating = getRatings(
379  recorded, m_progInfo.GetChanID(),
381  }
382 
383  if (category_type.isEmpty() && !m_progInfo.GetProgramID().isEmpty())
384  {
385  QString prefix = m_progInfo.GetProgramID().left(2);
386 
387  if (prefix == "MV")
388  category_type = "movie";
389  else if (prefix == "EP")
390  category_type = "series";
391  else if (prefix == "SP")
392  category_type = "sports";
393  else if (prefix == "SH")
394  category_type = "tvshow";
395  }
396 
397  addItem(tr("Title"),
400 
401  addItem(tr("Title Pronounce"), title_pronounce, ProgInfoList::kLevel2);
402 
403  QString s = m_progInfo.GetDescription();
404 
405  QString attr;
406 
407  if (partnumber > 0)
408  attr += tr("Part %1 of %2, ").arg(partnumber).arg(parttotal);
409 
410  if (!rating.isEmpty() && rating != "NR")
411  attr += rating + ", ";
412  if (category_type == "movie")
413  {
414  if (!year.isEmpty())
415  attr += year + ", ";
416 
417  /* see #7810, was hardcoded to 4 star system, when every theme
418  * uses 10 stars / 5 stars with half stars
419  */
420  if (stars > 0.0F)
421  attr += tr("%n star(s)", "", roundf(stars * 10.0F)) + ", ";
422  }
423  if (!colorcode.isEmpty())
424  attr += colorcode + ", ";
425 
426  if (audioprop & AUD_MONO)
427  attr += tr("Mono") + ", ";
428  if (audioprop & AUD_STEREO)
429  attr += tr("Stereo") + ", ";
430  if (audioprop & AUD_SURROUND)
431  attr += tr("Surround Sound") + ", ";
432  if (audioprop & AUD_DOLBY)
433  attr += tr("Dolby Sound") + ", ";
434  if (audioprop & AUD_HARDHEAR)
435  attr += tr("Audio for Hearing Impaired") + ", ";
436  if (audioprop & AUD_VISUALIMPAIR)
437  attr += tr("Audio for Visually Impaired") + ", ";
438 
439  if (videoprop & VID_HDTV)
440  attr += tr("HDTV") + ", ";
441  if (videoprop & VID_WIDESCREEN)
442  attr += tr("Widescreen") + ", ";
443  if (videoprop & VID_AVC)
444  attr += tr("AVC/H.264") + ", ";
445  if (videoprop & VID_HEVC)
446  attr += tr("HEVC/H.265") + ", ";
447  if (videoprop & VID_720)
448  attr += tr("720p Resolution") + ", ";
449 
450  if (videoprop & VID_PROGRESSIVE)
451  {
452  if (videoprop & VID_1080)
453  attr += tr("1080p Resolution") + ", ";
454  if (videoprop & VID_4K)
455  attr += tr("4K Resolution") + ", ";
456  }
457  else
458  {
459  if (videoprop & VID_1080)
460  attr += tr("1080i Resolution") + ", ";
461  if (videoprop & VID_4K)
462  attr += tr("4Ki Resolution") + ", ";
463  }
464 
465  if (videoprop & VID_DAMAGED)
466  attr += tr("Damaged") + ", ";
467 
468  if (subtype & SUB_HARDHEAR)
469  attr += tr("CC","Closed Captioned") + ", ";
470  if (subtype & SUB_NORMAL)
471  attr += tr("Subtitles Available") + ", ";
472  if (subtype & SUB_ONSCREEN)
473  attr += tr("Subtitled") + ", ";
474  if (subtype & SUB_SIGNED)
475  attr += tr("Deaf Signing") + ", ";
476 
477  if (generic && category_type == "series")
478  attr += tr("Unidentified Episode") + ", ";
479  else if (m_progInfo.IsRepeat())
480  attr += tr("Repeat") + ", ";
481 
482  if (!attr.isEmpty())
483  {
484  attr.truncate(attr.lastIndexOf(','));
485  s += " (" + attr + ")";
486  }
487 
488  addItem(tr("Description"), s, ProgInfoList::kLevel1);
489 
490  QString actors;
491  QString directors;
492  QString producers;
493  QString execProducers;
494  QString writers;
495  QString guestStars;
496  QString hosts;
497  QString adapters;
498  QString presenters;
499  QString commentators;
500  QString guests;
501 
502  using string_pair = QPair<QString, QString>;
503  QVector<string_pair> actor_list;
504  QVector<string_pair> guest_star_list;
505 
507  {
508  QString table;
509  if (recorded)
510  table = "recordedcredits";
511  else
512  table = "credits";
513 
514  query.prepare(QString("SELECT role, people.name, roles.name FROM %1"
515  " AS credits"
516  " LEFT JOIN people ON"
517  " credits.person = people.person"
518  " LEFT JOIN roles ON"
519  " credits.roleid = roles.roleid"
520  " WHERE credits.chanid = :CHANID"
521  " AND credits.starttime = :STARTTIME"
522  " ORDER BY role, priority;").arg(table));
523 
524  query.bindValue(":CHANID", m_progInfo.GetChanID());
525  query.bindValue(":STARTTIME", m_progInfo.GetScheduledStartTime());
526 
527  if (query.exec() && query.size() > 0)
528  {
529  QStringList plist;
530  QString rstr;
531  QString role;
532  QString pname;
533  QString character;
534 
535  while(query.next())
536  {
537  role = query.value(0).toString();
538  /* The people.name, roles.name columns uses utf8_bin collation.
539  * Qt-MySQL drivers use QVariant::ByteArray for string-type
540  * MySQL fields marked with the BINARY attribute (those using a
541  * *_bin collation) and QVariant::String for all others.
542  * Since QVariant::toString() uses QString::fromAscii()
543  * (through QVariant::convert()) when the QVariant's type is
544  * QVariant::ByteArray, we have to use QString::fromUtf8()
545  * explicitly to prevent corrupting characters.
546  * The following code should be changed to use the simpler
547  * toString() approach, as above, if we do a DB update to
548  * coalesce the people.name values that differ only in case and
549  * change the collation to utf8_general_ci, to match the
550  * majority of other columns, or we'll have the same problem in
551  * reverse.
552  */
553  pname = QString::fromUtf8(query.value(1)
554  .toByteArray().constData());
555  character = QString::fromUtf8(query.value(2)
556  .toByteArray().constData());
557 
558  if (!character.isEmpty())
559  {
560  if (role == "actor")
561  actor_list.append(qMakePair(pname, character));
562  else if (role == "guest_star")
563  guest_star_list.append(qMakePair(pname, character));
564  }
565 
566  if (rstr != role)
567  {
568  plist.removeDuplicates();
569  if (rstr == "actor")
570  actors = plist.join(", ");
571  else if (rstr == "director")
572  directors = plist.join(", ");
573  else if (rstr == "producer")
574  producers = plist.join(", ");
575  else if (rstr == "executive_producer")
576  execProducers = plist.join(", ");
577  else if (rstr == "writer")
578  writers = plist.join(", ");
579  else if (rstr == "guest_star")
580  guestStars = plist.join(", ");
581  else if (rstr == "host")
582  hosts = plist.join(", ");
583  else if (rstr == "adapter")
584  adapters = plist.join(", ");
585  else if (rstr == "presenter")
586  presenters = plist.join(", ");
587  else if (rstr == "commentator")
588  commentators = plist.join(", ");
589  else if (rstr == "guest")
590  guests = plist.join(", ");
591 
592  rstr = role;
593  plist.clear();
594  }
595 
596  plist.append(pname);
597  }
598  plist.removeDuplicates();
599  if (rstr == "actor")
600  actors = plist.join(", ");
601  else if (rstr == "director")
602  directors = plist.join(", ");
603  else if (rstr == "producer")
604  producers = plist.join(", ");
605  else if (rstr == "executive_producer")
606  execProducers = plist.join(", ");
607  else if (rstr == "writer")
608  writers = plist.join(", ");
609  else if (rstr == "guest_star")
610  guestStars = plist.join(", ");
611  else if (rstr == "host")
612  hosts = plist.join(", ");
613  else if (rstr == "adapter")
614  adapters = plist.join(", ");
615  else if (rstr == "presenter")
616  presenters = plist.join(", ");
617  else if (rstr == "commentator")
618  commentators = plist.join(", ");
619  else if (rstr == "guest")
620  guests = plist.join(", ");
621  }
622  }
623  addItem(tr("Actors"), actors, ProgInfoList::kLevel1);
624  addItem(tr("Guest Star"), guestStars, ProgInfoList::kLevel1);
625  addItem(tr("Guest"), guests, ProgInfoList::kLevel1);
626 
627  if (!actor_list.isEmpty())
628  {
629  for (const auto & [actor, role] : qAsConst(actor_list))
630  addItem(role, actor, ProgInfoList::kLevel2);
631  }
632  if (!guest_star_list.isEmpty())
633  {
634  for (const auto & [actor, role] : qAsConst(guest_star_list))
635  addItem(role, actor, ProgInfoList::kLevel2);
636  }
637 
638  addItem(tr("Host"), hosts, ProgInfoList::kLevel1);
639  addItem(tr("Presenter"), presenters, ProgInfoList::kLevel1);
640  addItem(tr("Commentator"), commentators, ProgInfoList::kLevel1);
641  addItem(tr("Director"), directors, ProgInfoList::kLevel1);
642  addItem(tr("Producer"), producers, ProgInfoList::kLevel2);
643  addItem(tr("Executive Producer"), execProducers, ProgInfoList::kLevel2);
644  addItem(tr("Writer"), writers, ProgInfoList::kLevel2);
645  addItem(tr("Adapter"), adapters, ProgInfoList::kLevel2);
646 
648 
649  query.prepare("SELECT genre FROM programgenres "
650  "WHERE chanid = :CHANID AND starttime = :STARTTIME "
651  "AND relevance <> '0' ORDER BY relevance;");
652  query.bindValue(":CHANID", m_progInfo.GetChanID());
653  query.bindValue(":STARTTIME", m_progInfo.GetScheduledStartTime());
654 
655  if (query.exec())
656  {
657  s.clear();
658  while (query.next())
659  {
660  if (!s.isEmpty())
661  s += ", ";
662  s += query.value(0).toString();
663  }
664  addItem(tr("Genre"), s, ProgInfoList::kLevel1);
665  }
666 
667  s.clear();
668  if (!category_type.isEmpty())
669  {
670  s = category_type;
671  if (!m_progInfo.GetSeriesID().isEmpty())
672  s += " (" + m_progInfo.GetSeriesID() + ")";
673  if (!showtype.isEmpty())
674  s += " " + showtype;
675  }
676  addItem(tr("Type", "category_type"), s, ProgInfoList::kLevel1);
677 
678  s.clear();
679  if (m_progInfo.GetSeason() > 0)
680  s = QString::number(m_progInfo.GetSeason());
681  addItem(tr("Season"), s, ProgInfoList::kLevel1);
682 
683  s.clear();
684  if (m_progInfo.GetEpisode() > 0)
685  {
686  if (m_progInfo.GetEpisodeTotal() > 0)
687  {
688  s = tr("%1 of %2").arg(m_progInfo.GetEpisode())
689  .arg(m_progInfo.GetEpisodeTotal());
690  }
691  else
692  {
693  s = QString::number(m_progInfo.GetEpisode());
694  }
695  }
696  addItem(tr("Episode"), s, ProgInfoList::kLevel1);
697 
698  addItem(tr("Syndicated Episode Number"), syndicatedEpisodeNum,
700 
701  s.clear();
702  if (m_progInfo.GetOriginalAirDate().isValid() &&
703  category_type != "movie")
704  {
707  }
708  addItem(tr("Original Airdate"), s, ProgInfoList::kLevel1);
709 
711 
712  // Begin MythTV information not found in the listings info
713  QDateTime statusDate;
716  statusDate = m_progInfo.GetScheduledStartTime();
717 
718  RecordingType rectype = kSingleRecord; // avoid kNotRecording
720 
721  if (recstatus == RecStatus::PreviousRecording ||
722  recstatus == RecStatus::NeverRecord ||
723  recstatus == RecStatus::Unknown)
724  {
725  query.prepare("SELECT recstatus, starttime "
726  "FROM oldrecorded WHERE duplicate > 0 AND "
727  "future = 0 AND "
728  "((programid <> '' AND programid = :PROGRAMID) OR "
729  " (title <> '' AND title = :TITLE AND "
730  " subtitle <> '' AND subtitle = :SUBTITLE AND "
731  " description <> '' AND description = :DECRIPTION));");
732 
733  query.bindValue(":PROGRAMID", m_progInfo.GetProgramID());
734  query.bindValue(":TITLE", m_progInfo.GetTitle());
735  query.bindValue(":SUBTITLE", m_progInfo.GetSubtitle());
736  query.bindValue(":DECRIPTION", m_progInfo.GetDescription());
737 
738  if (!query.exec())
739  {
740  MythDB::DBError("showDetails", query);
741  }
742  else if (query.next())
743  {
744  if (recstatus == RecStatus::Unknown)
745  recstatus = RecStatus::Type(query.value(0).toInt());
746 
747  if (recstatus == RecStatus::PreviousRecording ||
748  recstatus == RecStatus::NeverRecord ||
749  recstatus == RecStatus::Recorded)
750  {
751  statusDate = MythDate::as_utc(query.value(1).toDateTime());
752  }
753  }
754  }
755 
756  if (recstatus == RecStatus::Unknown)
757  {
758  if (recorded)
759  {
760  recstatus = RecStatus::Recorded;
761  statusDate = m_progInfo.GetScheduledStartTime();
762  }
763  else
764  {
765  // re-enable "Not Recording" status text
766  rectype = m_progInfo.GetRecordingRuleType();
767  }
768  }
769 
770  s = RecStatus::toString(recstatus, rectype);
771 
772  if (statusDate.isValid())
773  s += " " + MythDate::toString(statusDate, MythDate::kDateFull |
775 
776  addItem(tr("MythTV Status"), s, ProgInfoList::kLevel1);
777 
778  QString recordingRule;
779  QString lastRecorded;
780  QString nextRecording;
781  QString averageTimeShift;
782  QString watchListScore;
783  QString watchListStatus;
784  QString searchPhrase;
785 
787  {
788  recordingRule = QString("%1, ").arg(m_progInfo.GetRecordingRuleID());
790  recordingRule += toString(m_progInfo.GetRecordingRuleType());
791  if (record && !record->m_title.isEmpty())
792  recordingRule += QString(" \"%2\"").arg(record->m_title);
793 
794  query.prepare("SELECT last_record, next_record, avg_delay "
795  "FROM record WHERE recordid = :RECORDID");
796  query.bindValue(":RECORDID", m_progInfo.GetRecordingRuleID());
797 
798  if (query.exec() && query.next())
799  {
800  if (query.value(0).toDateTime().isValid())
801  {
802  lastRecorded = MythDate::toString(
803  MythDate::as_utc(query.value(0).toDateTime()),
805  }
806  if (query.value(1).toDateTime().isValid())
807  {
808  nextRecording = MythDate::toString(
809  MythDate::as_utc(query.value(1).toDateTime()),
811  }
812  if (query.value(2).toInt() > 0)
813  averageTimeShift = tr("%n hour(s)", "",
814  query.value(2).toInt());
815  }
816  if (recorded)
817  {
819  watchListScore =
820  QString::number(m_progInfo.GetRecordingPriority2());
821 
823  {
825  {
826  case wlExpireOff:
827  watchListStatus = tr("Auto-expire off");
828  break;
829  case wlWatched:
830  watchListStatus = tr("Marked as 'watched'");
831  break;
832  case wlEarlier:
833  watchListStatus = tr("Not the earliest episode");
834  break;
835  case wlDeleted:
836  watchListStatus = tr("Recently deleted episode");
837  break;
838  }
839  }
840  }
841  if (record && record->m_searchType != kManualSearch &&
843  searchPhrase = record->m_description;
844  }
845  addItem(tr("Recording Rule"), recordingRule, ProgInfoList::kLevel1);
846  addItem(tr("Search Phrase"), searchPhrase, ProgInfoList::kLevel1);
847 
848  s.clear();
849  if (m_progInfo.GetFindID())
850  {
851  QDateTime fdate(QDate(1970, 1, 1),QTime(12,0,0));
852  fdate = fdate.addDays((int)m_progInfo.GetFindID() - 719528);
853  s = QString("%1 (%2)").arg(m_progInfo.GetFindID())
854  .arg(MythDate::toString(
856  }
857  addItem(tr("Find ID"), s, ProgInfoList::kLevel2);
858 
859  addItem(tr("Last Recorded"), lastRecorded, ProgInfoList::kLevel2);
860  addItem(tr("Next Recording"), nextRecording, ProgInfoList::kLevel2);
861  addItem(tr("Average Time Shift"), averageTimeShift, ProgInfoList::kLevel2);
862  addItem(tr("Watch List Score"), watchListScore, ProgInfoList::kLevel2);
863  addItem(tr("Watch List Status"), watchListStatus, ProgInfoList::kLevel2);
864 
865  QString recordingHost;
866  QString recordingInput;
867  QString recordedID;
868  QString recordedPathname;
869  QString recordedFilename;
870  QString recordedFileSize;
871  QString recordingGroup;
872  QString storageGroup;
873  QString playbackGroup;
874  QString recordingProfile;
875 
876  recordingHost = m_progInfo.GetHostname();
877  recordingInput = m_progInfo.GetInputName();
878 
879  if (recorded)
880  {
881  recordedID = QString::number(m_progInfo.GetRecordingID());
882  recordedPathname = m_progInfo.GetPathname();
883  recordedFilename = m_progInfo.GetBasename();
884  recordedFileSize = QString("%1 ")
885  .arg(m_progInfo.GetFilesize()/((double)(1<<30)),0,'f',2);
886  recordedFileSize += tr("GB", "GigaBytes");
887 
888  query.prepare("SELECT profile FROM recorded"
889  " WHERE chanid = :CHANID"
890  " AND starttime = :STARTTIME;");
891  query.bindValue(":CHANID", m_progInfo.GetChanID());
892  query.bindValue(":STARTTIME", m_progInfo.GetRecordingStartTime());
893 
894  if (query.exec() && query.next())
895  {
896  recordingProfile = ProgramInfo::i18n(query.value(0).toString());
897  }
898  recordingGroup = ProgramInfo::i18n(m_progInfo.GetRecordingGroup());
899  storageGroup = ProgramInfo::i18n(m_progInfo.GetStorageGroup());
900  playbackGroup = ProgramInfo::i18n(m_progInfo.GetPlaybackGroup());
901  }
902  else if (m_progInfo.GetRecordingRuleID())
903  {
904  recordingProfile = record ? record->m_recProfile : tr("Unknown");
905  }
906  addItem(tr("Recording Host"), recordingHost, ProgInfoList::kLevel2);
907  addItem(tr("Recording Input"), recordingInput, ProgInfoList::kLevel2);
908  addItem(tr("Recorded ID"), recordedID, ProgInfoList::kLevel2);
909  addItem(tr("Recorded Pathname"), recordedPathname, ProgInfoList::kLevel2);
910  addItem(tr("Recorded File Name"), recordedFilename, ProgInfoList::kLevel1);
911  addItem(tr("Recorded File Size"), recordedFileSize, ProgInfoList::kLevel1);
912  addItem(tr("Recording Profile"), recordingProfile, ProgInfoList::kLevel2);
913  addItem(tr("Recording Group"), recordingGroup, ProgInfoList::kLevel1);
914  addItem(tr("Storage Group"), storageGroup, ProgInfoList::kLevel2);
915  addItem(tr("Playback Group"), playbackGroup, ProgInfoList::kLevel2);
916 
917  PowerPriorities(ptable);
918 
919  delete record;
920 }
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:216
RecordingRule::LoadByProgram
bool LoadByProgram(const ProgramInfo *proginfo)
Definition: recordingrule.cpp:168
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:807
RecStatus::Type
Type
Definition: recordingstatus.h:16
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
ProgDetails::m_progInfo
ProgramInfo m_progInfo
Definition: progdetails.h:36
ProgDetails::~ProgDetails
~ProgDetails() override
Definition: progdetails.cpp:92
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:215
ProgramInfo::GetFilesize
virtual uint64_t GetFilesize(void) const
Definition: programinfo.cpp:6345
RecordingRule::m_description
QString m_description
Definition: recordingrule.h:81
ProgramInfo::GetHostname
QString GetHostname(void) const
Definition: programinfo.h:421
ProgramInfo::GetInputName
QString GetInputName(void) const
Definition: programinfo.h:464
ProgInfoList::DataItem
std::tuple< QString, QString, int > DataItem
Definition: proginfolist.h:20
mythdb.h
MythDate::as_utc
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
Definition: mythdate.cpp:27
ProgDetails::addItem
void addItem(const QString &title, const QString &value, ProgInfoList::VisibleLevel level)
Definition: progdetails.cpp:110
RecStatus::NeverRecord
@ NeverRecord
Definition: recordingstatus.h:43
ProgInfoList::kLevel1
@ kLevel1
Definition: proginfolist.h:17
ProgDetails::updatePage
void updatePage(void)
Definition: progdetails.cpp:102
ProgramInfo::GetRecordingID
uint GetRecordingID(void) const
Definition: programinfo.h:446
RecordingRule::m_title
QString m_title
Definition: recordingrule.h:77
ProgramInfo::kTitleSubtitle
@ kTitleSubtitle
Definition: programinfo.h:509
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:205
ProgramInfo::GetCategory
QString GetCategory(void) const
Definition: programinfo.h:369
RecordingInfo::kReLeadingAnd
static const QRegularExpression kReLeadingAnd
Definition: recordinginfo.h:200
RecStatus::Unknown
@ Unknown
Definition: recordingstatus.h:32
RecordingRule
Internal representation of a recording rule, mirrors the record table.
Definition: recordingrule.h:28
ProgDetails::Create
bool Create(void) override
Definition: progdetails.cpp:19
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:608
RecStatus::Recorded
@ Recorded
Definition: recordingstatus.h:29
wlDeleted
@ wlDeleted
Definition: programtypes.h:188
ProgramInfo::GetScheduledEndTime
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:397
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
ProgramInfo::GetRecordingGroup
QString GetRecordingGroup(void) const
Definition: programinfo.h:419
progdetails.h
hardwareprofile.distros.mythtv_data.data_mythtv.prefix
string prefix
Definition: data_mythtv.py:40
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:404
ProgramInfo::GetPathname
QString GetPathname(void) const
Definition: programinfo.h:343
ProgDetails::PowerPriorities
void PowerPriorities(const QString &ptable)
Definition: progdetails.cpp:152
ProgInfoList::PageUp
void PageUp(void)
Definition: proginfolist.h:34
RecStatus::toString
static QString toString(RecStatus::Type recstatus, uint id)
Converts "recstatus" into a short (unreadable) string.
Definition: recordingstatus.cpp:40
ProgDetails::getRatings
static QString getRatings(bool recorded, uint chanid, const QDateTime &startts)
Definition: progdetails.cpp:38
ProgramInfo::IsRepeat
bool IsRepeat(void) const
Definition: programinfo.h:487
RecStatus::WillRecord
@ WillRecord
Definition: recordingstatus.h:31
mythdate.h
ProgDetails::loadPage
void loadPage(void)
Definition: progdetails.cpp:316
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:390
ProgramInfo::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:447
ProgInfoList::PageDown
void PageDown(void)
Definition: proginfolist.h:33
MythMainWindow::TranslateKeyPress
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
Definition: mythmainwindow.cpp:1104
ProgInfoList::Create
bool Create(bool focusable)
Initialise buttonlist from XML.
Definition: proginfolist.cpp:14
RecStatus::PreviousRecording
@ PreviousRecording
Definition: recordingstatus.h:34
ProgInfoList::Toggle
void Toggle(void)
Toggle infolist state. Focusable widgets toggle between Basic & Full info. Non-focusable widgets togg...
Definition: proginfolist.cpp:31
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:361
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:540
ProgramInfo::GetDescription
QString GetDescription(void) const
Definition: programinfo.h:365
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:227
ProgramInfo::GetEpisodeTotal
uint GetEpisodeTotal(void) const
Definition: programinfo.h:368
wlWatched
@ wlWatched
Definition: programtypes.h:190
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:206
hardwareprofile.scan.rating
def rating(profile, smoonURL, gate)
Definition: scan.py:39
RecordingRule::m_recProfile
QString m_recProfile
Definition: recordingrule.h:120
ProgInfoList::kLevel2
@ kLevel2
Definition: proginfolist.h:17
RecordingRule::m_searchType
RecSearchType m_searchType
Definition: recordingrule.h:112
ProgramInfo::toString
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
Definition: programinfo.cpp:1934
ProgInfoList::Display
void Display(const DataList &data)
Build list of key:value buttons.
Definition: proginfolist.cpp:96
ProgramInfo::GetPlaybackGroup
QString GetPlaybackGroup(void) const
Definition: programinfo.h:420
wlEarlier
@ wlEarlier
Definition: programtypes.h:189
ProgramInfo::GetFindID
uint GetFindID(void) const
Definition: programinfo.h:468
kManualSearch
@ kManualSearch
Definition: recordingtypes.h:85
uint
unsigned int uint
Definition: compat.h:79
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:54
ProgramInfo::GetSeriesID
QString GetSeriesID(void) const
Definition: programinfo.h:435
ProgramInfo::i18n
static QString i18n(const QString &msg)
Translations for play,recording, & storage groups +.
Definition: programinfo.cpp:5375
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:910
ProgramInfo::GetStorageGroup
QString GetStorageGroup(void) const
Definition: programinfo.h:422
ProgramInfo::GetOriginalAirDate
QDate GetOriginalAirDate(void) const
Definition: programinfo.h:428
RecStatus::Pending
@ Pending
Definition: recordingstatus.h:17
mythuihelper.h
ProgDetails::Init
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
Definition: progdetails.cpp:97
ProgDetails::m_data
ProgInfoList::DataList m_data
Definition: progdetails.h:38
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:372
ProgramInfo::GetRecordingRuleType
RecordingType GetRecordingRuleType(void) const
Definition: programinfo.h:451
ProgramInfo::GetEpisode
uint GetEpisode(void) const
Definition: programinfo.h:367
ProgDetails::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: progdetails.cpp:119
MythScreenType::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythscreentype.cpp:404
wlExpireOff
@ wlExpireOff
Definition: programtypes.h:191
MythDate::kAddYear
@ kAddYear
Add year to string if not included.
Definition: mythdate.h:25
ProgramInfo::GetSeason
uint GetSeason(void) const
Definition: programinfo.h:366
mythcorecontext.h
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:695
kNotRecording
@ kNotRecording
Definition: recordingtypes.h:22
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:883
kSingleRecord
@ kSingleRecord
Definition: recordingtypes.h:23
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:102
build_compdb.action
action
Definition: build_compdb.py:9
MythDate::kDateFull
@ kDateFull
Default local time.
Definition: mythdate.h:19
ProgramInfo::GetProgramID
QString GetProgramID(void) const
Definition: programinfo.h:436
ProgramInfo::GetRecordingPriority2
int GetRecordingPriority2(void) const
Definition: programinfo.h:441
ProgramInfo::GetRecordingRuleID
uint GetRecordingRuleID(void) const
Definition: programinfo.h:449
recordingrule.h
ProgramInfo::GetBasename
QString GetBasename(void) const
Definition: programinfo.h:344
mythmainwindow.h
ProgInfoList::Hide
bool Hide(void)
Remove infolist from display.
Definition: proginfolist.cpp:59
RecordingType
RecordingType
Definition: recordingtypes.h:20
ProgDetails::m_infoList
ProgInfoList m_infoList
Definition: progdetails.h:37
ProgInfoList::VisibleLevel
VisibleLevel
Definition: proginfolist.h:17
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:832
ProgramInfo::GetSubtitle
QString GetSubtitle(void) const
Definition: programinfo.h:363