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