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