MythTV  master
guidegrid.cpp
Go to the documentation of this file.
1 
2 #include "guidegrid.h"
3 
4 // c/c++
5 #include <algorithm>
6 #include <cstdint> // for uint64_t
7 #include <deque> // for _Deque_iterator, operator!=, etc
8 using namespace std;
9 
10 //qt
11 #include <QCoreApplication>
12 #include <QKeyEvent>
13 #include <QDateTime>
14 
15 // libmythbase
16 #include "mythdate.h"
17 #include "mythcorecontext.h"
18 #include "mythdbcon.h"
19 #include "mythlogging.h"
20 #include "autodeletedeque.h" // for AutoDeleteDeque, etc
21 #include "mythevent.h" // for MythEvent, etc
22 #include "mythtypes.h" // for InfoMap
23 
24 // libmyth
25 #include "programtypes.h" // for RecStatus, etc
26 
27 // libmythtv
28 #include "remoteutil.h"
29 #include "channelutil.h"
30 #include "cardutil.h"
31 #include "tvremoteutil.h"
32 #include "channelinfo.h"
33 #include "programinfo.h"
34 #include "recordingrule.h"
35 #include "tv_play.h"
36 #include "tv.h" // for ::kState_WatchingLiveTV
37 #include "tv_actions.h" // for ACTION_CHANNELSEARCH, etc
38 #include "recordingtypes.h" // for toString, etc
39 
40 // libmythui
41 #include "mythuibuttonlist.h"
42 #include "mythuiguidegrid.h"
43 #include "mythuistatetype.h"
44 #include "mythdialogbox.h"
45 #include "mythuiimage.h"
46 #include "mythuitext.h"
47 #include "mythmainwindow.h" // for GetMythMainWindow, etc
48 #include "mythrect.h" // for MythRect
49 #include "mythscreenstack.h" // for MythScreenStack
50 #include "mythscreentype.h" // for MythScreenType
51 #include "mythuiactions.h" // for ACTION_SELECT, ACTION_DOWN, etc
52 #include "mythuiutils.h" // for UIUtilW, UIUtilE
53 #include "mythgesture.h"
54 
55 // mythfrontend
56 #include "progfind.h"
57 
58 QWaitCondition epgIsVisibleCond;
59 
60 #define LOC QString("GuideGrid: ")
61 #define LOC_ERR QString("GuideGrid, Error: ")
62 #define LOC_WARN QString("GuideGrid, Warning: ")
63 
64 const QString kUnknownTitle = "";
65 //const QString kUnknownCategory = QObject::tr("Unknown");
66 const unsigned long kUpdateMS = 60 * 1000UL; // Grid update interval (mS)
67 static bool SelectionIsTunable(const ChannelInfoList &selection);
68 
70  JumpToChannelListener *parent, const QString &start_entry,
71  int start_chan_idx, int cur_chan_idx, uint rows_disp) :
72  m_listener(parent),
73  m_entry(start_entry),
74  m_previous_start_channel_index(start_chan_idx),
75  m_previous_current_channel_index(cur_chan_idx),
76  m_rows_displayed(rows_disp),
77  m_timer(new QTimer(this))
78 {
79  if (parent && m_timer)
80  {
81  connect(m_timer, SIGNAL(timeout()), SLOT(deleteLater()));
82  m_timer->setSingleShot(true);
83  }
84  Update();
85 }
86 
87 
89 {
90  if (m_listener)
91  {
92  m_listener->SetJumpToChannel(nullptr);
93  m_listener = nullptr;
94  }
95 
96  if (m_timer)
97  {
98  m_timer->stop();
99  m_timer = nullptr;
100  }
101 
102  QObject::deleteLater();
103 }
104 
105 
106 static bool has_action(const QString& action, const QStringList &actions)
107 {
108  QStringList::const_iterator it;
109  for (it = actions.begin(); it != actions.end(); ++it)
110  {
111  if (action == *it)
112  return true;
113  }
114  return false;
115 }
116 
117 bool JumpToChannel::ProcessEntry(const QStringList &actions, const QKeyEvent *e)
118 {
119  if (!m_listener)
120  return false;
121 
122  if (has_action("ESCAPE", actions))
123  {
126  deleteLater();
127  return true;
128  }
129 
130  if (has_action("DELETE", actions))
131  {
132  if (!m_entry.isEmpty())
133  m_entry = m_entry.left(m_entry.length()-1);
134  Update();
135  return true;
136  }
137 
138  if (has_action(ACTION_SELECT, actions))
139  {
140  if (Update())
141  deleteLater();
142  return true;
143  }
144 
145  QString txt = e->text();
146  bool isUInt;
147  txt.toUInt(&isUInt);
148  if (isUInt)
149  {
150  m_entry += txt;
151  Update();
152  return true;
153  }
154 
155  if (!m_entry.isEmpty() && (txt=="_" || txt=="-" || txt=="#" || txt=="."))
156  {
157  m_entry += txt;
158  Update();
159  return true;
160  }
161 
162  return false;
163 }
164 
166 {
167  if (!m_timer || !m_listener)
168  return false;
169 
170  m_timer->stop();
171 
172  // find the closest channel ...
173  int i = m_listener->FindChannel(0, m_entry, false);
174  if (i >= 0)
175  {
176  // setup the timeout timer for jump mode
178 
179  // rows_displayed to center
180  int start = i - m_rows_displayed/2;
181  int cur = m_rows_displayed/2;
182  m_listener->GoTo(start, cur);
183  return true;
184  }
185 
186  // prefix must be invalid.. reset entry..
188  return false;
189 }
190 
191 // GuideStatus is used for transferring the relevant read-only data
192 // from GuideGrid to the GuideUpdateProgramRow constructor.
194 {
195 public:
196  GuideStatus(unsigned int firstRow, unsigned int numRows,
197  const QVector<int> &channums,
198  const MythRect &gg_programRect,
199  int gg_channelCount,
200  const QDateTime &currentStartTime,
201  const QDateTime &currentEndTime,
202  uint currentStartChannel,
203  int currentRow, int currentCol,
204  int channelCount, int timeCount,
205  bool verticalLayout,
206  const QDateTime &firstTime, const QDateTime &lastTime)
207  : m_firstRow(firstRow), m_numRows(numRows), m_channums(channums),
208  m_gg_programRect(gg_programRect), m_gg_channelCount(gg_channelCount),
209  m_currentStartTime(currentStartTime),
210  m_currentEndTime(currentEndTime),
211  m_currentStartChannel(currentStartChannel), m_currentRow(currentRow),
212  m_currentCol(currentCol), m_channelCount(channelCount),
213  m_timeCount(timeCount), m_verticalLayout(verticalLayout),
214  m_firstTime(firstTime), m_lastTime(lastTime) {}
215  const unsigned int m_firstRow, m_numRows;
216  const QVector<int> m_channums;
218  const int m_gg_channelCount;
223  const bool m_verticalLayout;
224  const QDateTime m_firstTime, m_lastTime;
225 };
226 
228 {
229 public:
230  explicit GuideUpdaterBase(GuideGrid *guide) : m_guide(guide) {}
231  virtual ~GuideUpdaterBase() = default;
232 
233  // Execute the initial non-UI part (in a separate thread). Return
234  // true if ExecuteUI() should be run later, or false if the work
235  // is no longer relevant (e.g., the UI elements have scrolled
236  // offscreen by now).
237  virtual bool ExecuteNonUI(void) = 0;
238  // Execute the UI part in the UI thread.
239  virtual void ExecuteUI(void) = 0;
240 
241 protected:
242  GuideGrid *m_guide {nullptr};
243 };
244 
246 {
247 public:
249  const QVector<ProgramList*> &proglists)
250  : GuideUpdaterBase(guide),
252  m_numRows(gs.m_numRows),
266  m_proglists(proglists)
267  {
268  for (unsigned int i = m_firstRow;
269  i < m_firstRow + m_numRows; ++i)
270  for (int j = 0; j < MAX_DISPLAY_TIMES; ++j)
271  m_programInfos[i][j] = nullptr;
272  }
273  ~GuideUpdateProgramRow() override = default;
274  bool ExecuteNonUI(void) override // GuideUpdaterBase
275  {
276  // Don't bother to do any work if the starting coordinates of
277  // the guide have changed while the thread was waiting to
278  // start.
281  {
282  return false;
283  }
284 
285  for (unsigned int i = 0; i < m_numRows; ++i)
286  {
287  unsigned int row = i + m_firstRow;
288  if (!m_proglists[i])
289  m_proglists[i] =
293  m_proglists[i]);
294  }
295  return true;
296  }
297  void ExecuteUI(void) override // GuideUpdaterBase
298  {
302  }
303 
304 private:
305  void fillProgramRowInfosWith(int row, const QDateTime& start,
306  ProgramList *proglist);
307 
308  const unsigned int m_firstRow;
309  const unsigned int m_numRows;
310  const QVector<int> m_channums;
312  const int m_gg_channelCount;
313  const QDateTime m_currentStartTime;
314  const QDateTime m_currentEndTime;
316  const int m_currentRow;
317  const int m_currentCol;
318  const int m_channelCount;
319  const int m_timeCount;
320  const bool m_verticalLayout;
321  const QDateTime m_firstTime;
322  const QDateTime m_lastTime;
323 
324  QVector<ProgramList*> m_proglists;
326  int m_progPast {0};
327  //QVector<GuideUIElement> m_result;
328  QLinkedList<GuideUIElement> m_result;
329 };
330 
332 {
333 public:
334  GuideUpdateChannels(GuideGrid *guide, uint startChan)
335  : GuideUpdaterBase(guide), m_currentStartChannel(startChan) {}
336  bool ExecuteNonUI(void) override // GuideUpdaterBase
337  {
339  return false;
341  return true;
342  }
343  void ExecuteUI(void) override // GuideUpdaterBase
344  {
346  }
348  QVector<ChannelInfo *> m_chinfos;
349  QVector<bool> m_unavailables;
350 };
351 
352 class UpdateGuideEvent : public QEvent
353 {
354 public:
355  explicit UpdateGuideEvent(GuideUpdaterBase *updater) :
356  QEvent(kEventType), m_updater(updater) {}
358  static Type kEventType;
359 };
360 QEvent::Type UpdateGuideEvent::kEventType =
361  (QEvent::Type) QEvent::registerEventType();
362 
363 class GuideHelper : public QRunnable
364 {
365 public:
367  : m_guide(guide), m_updater(updater)
368  {
369  QMutexLocker locker(&s_lock);
370  ++s_loading[m_guide];
371  }
372  void run(void) override // QRunnable
373  {
374  QThread::currentThread()->setPriority(QThread::IdlePriority);
375  if (m_updater)
376  {
377  if (m_updater->ExecuteNonUI())
378  QCoreApplication::postEvent(m_guide,
380  else
381  {
382  delete m_updater;
383  m_updater = nullptr;
384  }
385  }
386 
387  QMutexLocker locker(&s_lock);
388  --s_loading[m_guide];
389  if (!s_loading[m_guide])
390  s_wait.wakeAll();
391  }
392  static bool IsLoading(GuideGrid *guide)
393  {
394  QMutexLocker locker(&s_lock);
395  return s_loading[guide] != 0U;
396  }
397  static void Wait(GuideGrid *guide)
398  {
399  QMutexLocker locker(&s_lock);
400  while (s_loading[guide])
401  {
402  if (!s_wait.wait(locker.mutex(), 15000UL))
403  return;
404  }
405  }
406 private:
407  GuideGrid *m_guide {nullptr};
409 
410  static QMutex s_lock;
411  static QWaitCondition s_wait;
412  static QMap<GuideGrid*,uint> s_loading;
413 };
414 QMutex GuideHelper::s_lock;
415 QWaitCondition GuideHelper::s_wait;
416 QMap<GuideGrid*,uint> GuideHelper::s_loading;
417 
418 void GuideGrid::RunProgramGuide(uint chanid, const QString &channum,
419  const QDateTime &startTime,
420  TV *player, bool embedVideo,
421  bool allowFinder, int changrpid)
422 {
423  // which channel group should we default to
424  if (changrpid == -2)
425  changrpid = gCoreContext->GetNumSetting("ChannelGroupDefault", -1);
426 
427  // check there are some channels setup
429  0, true, "", (changrpid<0) ? 0 : changrpid);
430  if (channels.empty())
431  {
432  QString message;
433  if (changrpid == -1)
434  {
435  message = tr("You don't have any channels defined in the database."
436  "\n\t\t\tThe program guide will have nothing to show you.");
437  }
438  else
439  {
440  message = tr("Channel group '%1' doesn't have any channels defined."
441  "\n\t\t\tThe program guide will have nothing to show you.")
442  .arg(ChannelGroup::GetChannelGroupName(changrpid));
443  }
444 
445  LOG(VB_GENERAL, LOG_WARNING, LOC + message);
446 
447  if (!player)
448  ShowOkPopup(message);
449  else
450  {
451  if (player && allowFinder)
452  {
453  message = QString("EPG_EXITING");
454  qApp->postEvent(player, new MythEvent(message));
455  }
456  }
457 
458  return;
459  }
460 
461  // If chanid/channum are unset, find the channel that would
462  // naturally be selected when Live TV is started. This depends on
463  // the available tuners, their capturecard.livetvorder values, and
464  // their capturecard.startchan values.
465  QString actualChannum = channum;
466  if (chanid == 0 && actualChannum.isEmpty())
467  {
468  uint defaultChanid = gCoreContext->GetNumSetting("DefaultChanid", 0);
469  if (defaultChanid && TV::IsTunable(defaultChanid))
470  chanid = defaultChanid;
471  }
472  if (chanid == 0 && actualChannum.isEmpty())
473  {
474  vector<uint> inputIDs = RemoteRequestFreeInputList(0);
475  if (!inputIDs.empty())
476  actualChannum = CardUtil::GetStartingChannel(inputIDs[0]);
477  }
478 
480  GuideGrid *gg = new GuideGrid(mainStack,
481  chanid, actualChannum, startTime,
482  player, embedVideo, allowFinder,
483  changrpid);
484 
485  if (gg->Create())
486  mainStack->AddScreen(gg, (player == nullptr));
487  else
488  delete gg;
489 }
490 
492  uint chanid, const QString &channum, const QDateTime &startTime,
493  TV *player, bool embedVideo,
494  bool allowFinder, int changrpid)
495  : ScheduleCommon(parent, "guidegrid"),
496  m_selectRecThreshold(gCoreContext->GetNumSetting("SelChangeRecThreshold", 16)),
497  m_allowFinder(allowFinder),
498  m_startChanID(chanid),
499  m_startChanNum(channum),
500  m_sortReverse(gCoreContext->GetBoolSetting("EPGSortReverse", false)),
501  m_player(player),
502  m_embedVideo(embedVideo),
503  m_previewVideoRefreshTimer(new QTimer(this)),
504  m_channelOrdering(gCoreContext->GetSetting("ChannelOrdering", "channum")),
505  m_updateTimer(new QTimer(this)),
506  m_threadPool("GuideGridHelperPool"),
507  m_changrpid(changrpid),
508  m_changrplist(ChannelGroup::GetChannelGroups(false))
509 {
510  connect(m_previewVideoRefreshTimer, SIGNAL(timeout()),
511  this, SLOT(refreshVideo()));
512  connect(m_updateTimer, SIGNAL(timeout()), SLOT(updateTimeout()) );
513 
514  for (uint i = 0; i < MAX_DISPLAY_CHANS; i++)
515  m_programs.push_back(nullptr);
516 
517  for (int x = 0; x < MAX_DISPLAY_TIMES; ++x)
518  {
519  for (int y = 0; y < MAX_DISPLAY_CHANS; ++y)
520  m_programInfos[y][x] = nullptr;
521  }
522 
524  if (startTime.isValid() &&
525  startTime > m_originalStartTime.addSecs(-8 * 3600))
526  m_originalStartTime = startTime;
527 
528  int secsoffset = -((m_originalStartTime.time().minute() % 30) * 60 +
529  m_originalStartTime.time().second());
530  m_currentStartTime = m_originalStartTime.addSecs(secsoffset);
532 }
533 
535 {
536  QString windowName = "programguide";
537 
538  if (m_embedVideo)
539  windowName = "programguide-video";
540 
541  if (!LoadWindowFromXML("schedule-ui.xml", windowName, this))
542  return false;
543 
544  bool err = false;
545  UIUtilE::Assign(this, m_timeList, "timelist", &err);
546  UIUtilE::Assign(this, m_channelList, "channellist", &err);
547  UIUtilE::Assign(this, m_guideGrid, "guidegrid", &err);
548  UIUtilW::Assign(this, m_dateText, "datetext");
549  UIUtilW::Assign(this, m_longdateText, "longdatetext");
550  UIUtilW::Assign(this, m_changroupname, "channelgroup");
551  UIUtilW::Assign(this, m_channelImage, "channelicon");
552  UIUtilW::Assign(this, m_jumpToText, "jumptotext");
553 
554  if (err)
555  {
556  LOG(VB_GENERAL, LOG_ERR,
557  QString("Cannot load screen '%1'").arg(windowName));
558  return false;
559  }
560 
561  BuildFocusList();
562 
563  MythUIImage *videoImage = dynamic_cast<MythUIImage *>(GetChild("video"));
564  if (videoImage && m_embedVideo)
565  m_videoRect = videoImage->GetArea();
566  else
567  m_videoRect = QRect(0,0,0,0);
568 
572 
573  m_currentEndTime = m_currentStartTime.addSecs(m_timeCount * 60 * 5);
574 
576  return true;
577 }
578 
579 void GuideGrid::Load(void)
580 {
583 
584  int maxchannel = max((int)GetChannelCount() - 1, 0);
586  m_channelCount = min(m_channelCount, maxchannel + 1);
587 
588  for (int y = 0; y < m_channelCount; ++y)
589  {
590  int chanNum = y + m_currentStartChannel;
591  if (chanNum >= (int) m_channelInfos.size())
592  chanNum -= (int) m_channelInfos.size();
593  if (chanNum >= (int) m_channelInfos.size())
594  continue;
595 
596  if (chanNum < 0)
597  chanNum = 0;
598 
599  delete m_programs[y];
601  }
602 }
603 
604 void GuideGrid::Init(void)
605 {
607  m_currentCol = 0;
608 
609  fillTimeInfos();
610 
611  updateChannels();
612 
613  fillProgramInfos(true);
614 
615  m_updateTimer->start(kUpdateMS);
616 
617  updateDateText();
618 
619  QString changrpname = ChannelGroup::GetChannelGroupName(m_changrpid);
620 
621  if (m_changroupname)
622  m_changroupname->SetText(changrpname);
623 
624  gCoreContext->addListener(this);
625 }
626 
628 {
629  m_updateTimer->disconnect(this);
630  m_updateTimer = nullptr;
631 
632  GuideHelper::Wait(this);
633 
635 
636  while (!m_programs.empty())
637  {
638  if (m_programs.back())
639  delete m_programs.back();
640  m_programs.pop_back();
641  }
642 
643  m_channelInfos.clear();
644 
646  {
647  m_previewVideoRefreshTimer->disconnect(this);
648  m_previewVideoRefreshTimer = nullptr;
649  }
650 
651  gCoreContext->SaveSetting("EPGSortReverse", m_sortReverse ? "1" : "0");
652 
653  // if we have a player and we are returning to it we need
654  // to tell it to stop embedding and return to fullscreen
655  if (m_player && m_allowFinder)
656  {
657  QString message = QString("EPG_EXITING");
658  qApp->postEvent(m_player, new MythEvent(message));
659  }
660 
661  // maybe the user selected a different channel group,
662  // tell the player to update its channel list just in case
663  if (m_player)
665 
666  if (gCoreContext->GetBoolSetting("ChannelGroupRememberLast", false))
667  gCoreContext->SaveSetting("ChannelGroupDefault", m_changrpid);
668 }
669 
670 bool GuideGrid::keyPressEvent(QKeyEvent *event)
671 {
672  QStringList actions;
673  bool handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend", event, actions);
674 
675  if (handled)
676  return true;
677 
678  if (!actions.empty())
679  {
680  QMutexLocker locker(&m_jumpToChannelLock);
681 
682  if (!m_jumpToChannel)
683  {
684  QString chanNum = actions[0];
685  bool isNum;
686  (void)chanNum.toInt(&isNum);
687  if (isNum)
688  {
689  // see if we can find a matching channel before creating the JumpToChannel otherwise
690  // JumpToChannel will delete itself in the ctor leading to a segfault
691  int i = FindChannel(0, chanNum, false);
692  if (i >= 0)
693  {
694  m_jumpToChannel = new JumpToChannel(this, chanNum,
698  }
699 
700  handled = true;
701  }
702  }
703 
704  if (m_jumpToChannel && !handled)
705  handled = m_jumpToChannel->ProcessEntry(actions, event);
706  }
707 
708  for (int i = 0; i < actions.size() && !handled; ++i)
709  {
710  QString action = actions[i];
711  handled = true;
712  if (action == ACTION_UP)
713  {
714  if (m_verticalLayout)
715  cursorLeft();
716  else
717  cursorUp();
718  }
719  else if (action == ACTION_DOWN)
720  {
721  if (m_verticalLayout)
722  cursorRight();
723  else
724  cursorDown();
725  }
726  else if (action == ACTION_LEFT)
727  {
728  if (m_verticalLayout)
729  cursorUp();
730  else
731  cursorLeft();
732  }
733  else if (action == ACTION_RIGHT)
734  {
735  if (m_verticalLayout)
736  cursorDown();
737  else
738  cursorRight();
739  }
740  else if (action == "PAGEUP")
741  {
742  if (m_verticalLayout)
744  else
746  }
747  else if (action == "PAGEDOWN")
748  {
749  if (m_verticalLayout)
751  else
753  }
754  else if (action == ACTION_PAGELEFT)
755  {
756  if (m_verticalLayout)
758  else
760  }
761  else if (action == ACTION_PAGERIGHT)
762  {
763  if (m_verticalLayout)
765  else
767  }
768  else if (action == ACTION_DAYLEFT)
770  else if (action == ACTION_DAYRIGHT)
772  else if (action == "NEXTFAV")
774  else if (action == ACTION_FINDER)
775  showProgFinder();
776  else if (action == ACTION_CHANNELSEARCH)
778  else if (action == "MENU")
779  ShowMenu();
780  else if (action == "ESCAPE" || action == ACTION_GUIDE)
781  Close();
782  else if (action == ACTION_SELECT)
783  {
784  ProgramInfo *pginfo =
786  int secsTillStart =
787  (pginfo) ? MythDate::current().secsTo(
788  pginfo->GetScheduledStartTime()) : 0;
790  {
791  // See if this show is far enough into the future that it's
792  // probable that the user wanted to schedule it to record
793  // instead of changing the channel.
794  if (pginfo && (pginfo->GetTitle() != kUnknownTitle) &&
795  ((secsTillStart / 60) >= m_selectRecThreshold))
796  {
797  EditRecording();
798  }
799  else
800  {
801  enter();
802  }
803  }
804  else
805  // Edit Recording should include "Watch this channel"
806  // is we selected a show that is current.
809  && (secsTillStart / 60) < m_selectRecThreshold);
810  }
811  else if (action == "EDIT")
812  EditScheduled();
813  else if (action == "CUSTOMEDIT")
814  EditCustom();
815  else if (action == "DELETE")
816  deleteRule();
817  else if (action == "UPCOMING")
818  ShowUpcoming();
819  else if (action == "PREVRECORDED")
820  ShowPrevious();
821  else if (action == "DETAILS" || action == "INFO")
822  ShowDetails();
823  else if (action == ACTION_TOGGLERECORD)
824  QuickRecord();
825  else if (action == ACTION_TOGGLEFAV)
826  {
827  if (m_changrpid == -1)
828  ChannelGroupMenu(0);
829  else
831  }
832  else if (action == "CHANUPDATE")
833  channelUpdate();
834  else if (action == ACTION_VOLUMEUP)
835  volumeUpdate(true);
836  else if (action == ACTION_VOLUMEDOWN)
837  volumeUpdate(false);
838  else if (action == "CYCLEAUDIOCHAN")
839  toggleMute(true);
840  else if (action == ACTION_MUTEAUDIO)
841  toggleMute();
842  else if (action == ACTION_TOGGLEPGORDER)
843  {
846  updateChannels();
847  }
848  else
849  handled = false;
850  }
851 
852  if (!handled && MythScreenType::keyPressEvent(event))
853  handled = true;
854 
855  return handled;
856 }
857 
859 {
860  bool handled = true;
861 
862  if (!event)
863  {
864  LOG(VB_GENERAL, LOG_INFO, LOC + "Guide Gesture no event");
865  return false;
866  }
867 
868  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Guide Gesture event %1")
869  .arg((QString)event->gesture()));
870  switch (event->gesture())
871  {
873  {
874  handled = false;
875 
876  // We want the relative position of the click
877  QPoint position = event->GetPosition();
878  if (m_Parent)
879  position -= m_Parent->GetArea().topLeft();
880 
881  MythUIType *type = GetChildAt(position, false, false);
882 
883  if (!type)
884  return false;
885 
886  MythUIStateType *object = dynamic_cast<MythUIStateType *>(type);
887 
888  if (object)
889  {
890  QString name = object->objectName();
891  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Guide Gesture Click name %1").arg(name));
892 
893  if (name.startsWith("channellist"))
894  {
895  MythUIButtonList* channelList = dynamic_cast<MythUIButtonList*>(object);
896 
897  if (channelList)
898  {
899  handled = channelList->gestureEvent(event);
900  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Guide Gesture Click channel list %1").arg(handled));
901  }
902  }
903  else if (name.startsWith("guidegrid"))
904  {
905  MythUIGuideGrid* guidegrid = dynamic_cast<MythUIGuideGrid*>(object);
906 
907  if (guidegrid)
908  {
909  handled = true;
910 
911  QPoint rowCol = guidegrid->GetRowAndColumn(position - guidegrid->GetArea().topLeft());
912 
913  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Guide Gesture Click gg %1,%2 (%3,%4)")
914  .arg(rowCol.y())
915  .arg(rowCol.x())
916  .arg(m_currentRow)
917  .arg(m_currentCol)
918  );
919  if ((rowCol.y() >= 0) && (rowCol.x() >= 0))
920  {
921  if ((rowCol.y() == m_currentRow) && (rowCol.x() == m_currentCol))
922  {
924  {
925  // See if this show is far enough into the future that it's
926  // probable that the user wanted to schedule it to record
927  // instead of changing the channel.
928  ProgramInfo *pginfo =
930  int secsTillStart =
931  (pginfo) ? MythDate::current().secsTo(
932  pginfo->GetScheduledStartTime()) : 0;
933  if (pginfo && (pginfo->GetTitle() != kUnknownTitle) &&
934  ((secsTillStart / 60) >= m_selectRecThreshold))
935  {
936  //EditRecording();
937  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Guide Gesture Click gg EditRec"));
938  }
939  else
940  {
941  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Guide Gesture Click gg enter"));
942  enter();
943  }
944  }
945  else
946  {
947  //EditRecording();
948  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Guide Gesture Click gg not live"));
949  }
950  }
951  else
952  {
953  bool rowChanged = (rowCol.y() != m_currentRow);
954  bool colChanged = (rowCol.x() != m_currentCol);
955  if (rowChanged)
957 
958  m_currentRow = rowCol.y();
959  m_currentCol = rowCol.x();
960 
962  if (colChanged)
963  {
964  m_currentStartTime = m_programInfos[m_currentRow][m_currentCol]->GetScheduledStartTime();
965  fillTimeInfos();
966  }
967  if (rowChanged)
968  updateChannels();
969  if (colChanged)
970  updateDateText();
971  }
972  }
973  }
974  }
975 
976  }
977  }
978  break;
979 
981  if (m_verticalLayout)
982  cursorLeft();
983  else
984  cursorUp();
985  break;
986 
988  if (m_verticalLayout)
989  cursorRight();
990  else
991  cursorDown();
992  break;
993 
995  if (m_verticalLayout)
996  cursorUp();
997  else
998  cursorLeft();
999  break;
1000 
1002  if (m_verticalLayout)
1003  cursorDown();
1004  else
1005  cursorRight();
1006  break;
1007 
1009  if (m_verticalLayout)
1011  else
1013  break;
1014 
1016  if (m_verticalLayout)
1018  else
1020  break;
1021 
1023  if (m_verticalLayout)
1025  else
1027  break;
1028 
1030  if (m_verticalLayout)
1032  else
1034  break;
1035 
1038  break;
1039 
1042  break;
1043 
1045  enter();
1046  break;
1047 
1048  default:
1049  handled = false;
1050  break;
1051  }
1052 
1053  if (!handled && MythScreenType::gestureEvent(event))
1054  handled = true;
1055 
1056  return handled;
1057 }
1058 
1059 static bool SelectionIsTunable(const ChannelInfoList &selection)
1060 {
1061  for (size_t i = 0; i < selection.size(); ++i)
1062  {
1063  if (TV::IsTunable(selection[i].m_chanid))
1064  return true;
1065  }
1066  return false;
1067 }
1068 
1070 {
1071  QString label = tr("Guide Options");
1072 
1073  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1074  MythDialogBox *menuPopup = new MythDialogBox(label, popupStack,
1075  "guideMenuPopup");
1076 
1077  if (menuPopup->Create())
1078  {
1079  menuPopup->SetReturnEvent(this, "guidemenu");
1080 
1082  menuPopup->AddButton(tr("Change to Channel"));
1083  else if (!m_player && SelectionIsTunable(GetSelection()))
1084  menuPopup->AddButton(tr("Watch This Channel"));
1085 
1086  menuPopup->AddButton(tr("Record This"));
1087 
1088  menuPopup->AddButton(tr("Recording Options"), nullptr, true);
1089 
1090  menuPopup->AddButton(tr("Program Details"));
1091 
1092  menuPopup->AddButton(tr("Jump to Time"), nullptr, true);
1093 
1094  menuPopup->AddButton(tr("Reverse Channel Order"));
1095 
1096  menuPopup->AddButton(tr("Channel Search"));
1097 
1098  if (!m_changrplist.empty())
1099  {
1100  menuPopup->AddButton(tr("Choose Channel Group"));
1101 
1102  if (m_changrpid == -1)
1103  menuPopup->AddButton(tr("Add To Channel Group"), nullptr, true);
1104  else
1105  menuPopup->AddButton(tr("Remove from Channel Group"), nullptr, true);
1106  }
1107 
1108  popupStack->AddScreen(menuPopup);
1109  }
1110  else
1111  {
1112  delete menuPopup;
1113  }
1114 }
1115 
1117 {
1118  QString label = tr("Recording Options");
1119 
1120  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1121  MythDialogBox *menuPopup = new MythDialogBox(label, popupStack,
1122  "recMenuPopup");
1123 
1124  if (menuPopup->Create())
1125  {
1126  menuPopup->SetReturnEvent(this, "recmenu");
1127 
1129 
1130  if (pginfo && pginfo->GetRecordingRuleID())
1131  menuPopup->AddButton(tr("Edit Recording Status"));
1132  menuPopup->AddButton(tr("Edit Schedule"));
1133  menuPopup->AddButton(tr("Show Upcoming"));
1134  menuPopup->AddButton(tr("Previously Recorded"));
1135  menuPopup->AddButton(tr("Custom Edit"));
1136 
1137  if (pginfo && pginfo->GetRecordingRuleID())
1138  menuPopup->AddButton(tr("Delete Rule"));
1139 
1140  popupStack->AddScreen(menuPopup);
1141  }
1142  else
1143  {
1144  delete menuPopup;
1145  }
1146 }
1147 
1149 {
1150  sel = (sel >= 0) ? sel : m_channelInfoIdx[chan_idx];
1151 
1152  if (chan_idx >= GetChannelCount())
1153  return nullptr;
1154 
1155  if (sel >= (int) m_channelInfos[chan_idx].size())
1156  return nullptr;
1157 
1158  return &(m_channelInfos[chan_idx][sel]);
1159 }
1160 
1161 const ChannelInfo *GuideGrid::GetChannelInfo(uint chan_idx, int sel) const
1162 {
1163  return ((GuideGrid*)this)->GetChannelInfo(chan_idx, sel);
1164 }
1165 
1167 {
1168  return m_channelInfos.size();
1169 }
1170 
1172 {
1173  uint cnt = GetChannelCount();
1174  if (!cnt)
1175  return -1;
1176 
1177  row = (row < 0) ? m_currentRow : row;
1178  return (row + m_currentStartChannel) % cnt;
1179 }
1180 
1182 {
1183  ProgramList proglist;
1184  MSqlBindings bindings;
1185  QString querystr =
1186  "WHERE program.chanid = :CHANID AND "
1187  " program.endtime >= :STARTTS AND "
1188  " program.starttime <= :ENDTS AND "
1189  " program.starttime >= :STARTLIMITTS AND "
1190  " program.manualid = 0 ";
1191  QDateTime starttime = m_currentStartTime.addSecs(0 - m_currentStartTime.time().second());
1192  bindings[":STARTTS"] = starttime;
1193  bindings[":STARTLIMITTS"] = starttime.addDays(-1);
1194  bindings[":ENDTS"] = m_currentEndTime.addSecs(0 - m_currentEndTime.time().second());
1195  bindings[":CHANID"] = chanid;
1196 
1197  ProgramList dummy;
1198  LoadFromProgram(proglist, querystr, bindings, dummy);
1199 
1200  return proglist;
1201 }
1202 
1204 {
1205  if (!proglist)
1206  return nullptr;
1207  ProgramList *result = new ProgramList();
1208  for (ProgramList::iterator pi = proglist->begin();
1209  pi != proglist->end(); ++pi)
1210  result->push_back(new ProgramInfo(**pi));
1211  return result;
1212 }
1213 
1215  uint chan_idx, bool with_same_channum) const
1216 {
1217  uint si = m_channelInfoIdx[chan_idx];
1218  const ChannelInfo *chinfo = GetChannelInfo(chan_idx, si);
1219 
1220  PlayerContext *ctx = m_player->GetPlayerReadLock(-1, __FILE__, __LINE__);
1221 
1222  const uint cnt = (ctx && chinfo) ? m_channelInfos[chan_idx].size() : 0;
1223  for (uint i = 0; i < cnt; ++i)
1224  {
1225  if (i == si)
1226  continue;
1227 
1228  const ChannelInfo *ciinfo = GetChannelInfo(chan_idx, i);
1229  if (!ciinfo)
1230  continue;
1231 
1232  bool same_channum = ciinfo->m_channum == chinfo->m_channum;
1233 
1234  if (with_same_channum != same_channum)
1235  continue;
1236 
1237  if (!m_player->IsTunable(ctx, ciinfo->m_chanid))
1238  continue;
1239 
1240  if (with_same_channum)
1241  {
1242  si = i;
1243  break;
1244  }
1245 
1246  ProgramList proglist = GetProgramList(chinfo->m_chanid);
1247  ProgramList ch_proglist = GetProgramList(ciinfo->m_chanid);
1248 
1249  if (proglist.empty() ||
1250  proglist.size() != ch_proglist.size())
1251  continue;
1252 
1253  bool isAlt = true;
1254  for (size_t j = 0; j < proglist.size(); ++j)
1255  {
1256  isAlt &= proglist[j]->IsSameTitleTimeslotAndChannel(*ch_proglist[j]);
1257  }
1258 
1259  if (isAlt)
1260  {
1261  si = i;
1262  break;
1263  }
1264  }
1265 
1266  m_player->ReturnPlayerLock(ctx);
1267 
1268  return si;
1269 }
1270 
1271 
1272 #define MKKEY(IDX,SEL) ((((uint64_t)(IDX)) << 32) | (SEL))
1274 {
1275  ChannelInfoList selected;
1276 
1277  int idx = GetStartChannelOffset();
1278  if (idx < 0)
1279  return selected;
1280 
1281  uint si = m_channelInfoIdx[idx];
1282 
1283  vector<uint64_t> sel;
1284  sel.push_back( MKKEY(idx, si) );
1285 
1286  const ChannelInfo *ch = GetChannelInfo(sel[0]>>32, sel[0]&0xffff);
1287  if (!ch)
1288  return selected;
1289 
1290  selected.push_back(*ch);
1291  if (m_channelInfos[idx].size() <= 1)
1292  return selected;
1293 
1294  ProgramList proglist = GetProgramList(selected[0].m_chanid);
1295 
1296  if (proglist.empty())
1297  return selected;
1298 
1299  for (size_t i = 0; i < m_channelInfos[idx].size(); ++i)
1300  {
1301  const ChannelInfo *ci = GetChannelInfo(idx, i);
1302  if (ci && (i != si) &&
1303  (ci->m_callsign == ch->m_callsign) && (ci->m_channum == ch->m_channum))
1304  {
1305  sel.push_back( MKKEY(idx, i) );
1306  }
1307  }
1308 
1309  for (size_t i = 0; i < m_channelInfos[idx].size(); ++i)
1310  {
1311  const ChannelInfo *ci = GetChannelInfo(idx, i);
1312  if (ci && (i != si) &&
1313  (ci->m_callsign == ch->m_callsign) && (ci->m_channum != ch->m_channum))
1314  {
1315  sel.push_back( MKKEY(idx, i) );
1316  }
1317  }
1318 
1319  for (size_t i = 0; i < m_channelInfos[idx].size(); ++i)
1320  {
1321  const ChannelInfo *ci = GetChannelInfo(idx, i);
1322  if ((i != si) && (ci->m_callsign != ch->m_callsign))
1323  {
1324  sel.push_back( MKKEY(idx, i) );
1325  }
1326  }
1327 
1328  for (size_t i = 1; i < sel.size(); ++i)
1329  {
1330  const ChannelInfo *ci = GetChannelInfo(sel[i]>>32, sel[i]&0xffff);
1331  const ProgramList ch_proglist = GetProgramList(ch->m_chanid);
1332 
1333  if (!ci || proglist.size() != ch_proglist.size())
1334  continue;
1335 
1336  bool isAlt = true;
1337  for (size_t j = 0; j < proglist.size(); ++j)
1338  {
1339  isAlt &= proglist[j]->IsSameTitleTimeslotAndChannel(*ch_proglist[j]);
1340  }
1341 
1342  if (isAlt)
1343  selected.push_back(*ci);
1344  }
1345 
1346  return selected;
1347 }
1348 #undef MKKEY
1349 
1351 {
1352  m_updateTimer->stop();
1353  fillProgramInfos();
1354  m_updateTimer->start(kUpdateMS);
1355 }
1356 
1357 void GuideGrid::fillChannelInfos(bool gotostartchannel)
1358 {
1359  m_channelInfos.clear();
1360  m_channelInfoIdx.clear();
1362 
1363  uint avail = 0;
1364  const ChannelUtil::OrderBy ordering = m_channelOrdering == "channum" ?
1366  ChannelInfoList channels = ChannelUtil::LoadChannels(0, 0, avail, true,
1367  ordering,
1369  0,
1370  (m_changrpid < 0) ? 0 : m_changrpid);
1371 
1372  typedef vector<uint> uint_list_t;
1373  QMap<QString,uint_list_t> channum_to_index_map;
1374  QMap<QString,uint_list_t> callsign_to_index_map;
1375 
1376  for (size_t i = 0; i < channels.size(); ++i)
1377  {
1378  uint chan = i;
1379  if (m_sortReverse)
1380  {
1381  chan = channels.size() - i - 1;
1382  }
1383 
1384  bool ndup = !channum_to_index_map[channels[chan].m_channum].empty();
1385  bool cdup = !callsign_to_index_map[channels[chan].m_callsign].empty();
1386 
1387  if (ndup && cdup)
1388  continue;
1389 
1390  ChannelInfo val(channels[chan]);
1391 
1392  channum_to_index_map[val.m_channum].push_back(GetChannelCount());
1393  callsign_to_index_map[val.m_callsign].push_back(GetChannelCount());
1394 
1395  // add the new channel to the list
1397  tmp.push_back(val);
1398  m_channelInfos.push_back(tmp);
1399  }
1400 
1401  // handle duplicates
1402  for (size_t i = 0; i < channels.size(); ++i)
1403  {
1404  const uint_list_t &ndups = channum_to_index_map[channels[i].m_channum];
1405  for (size_t j = 0; j < ndups.size(); ++j)
1406  {
1407  if (channels[i].m_chanid != m_channelInfos[ndups[j]][0].m_chanid &&
1408  channels[i].m_callsign == m_channelInfos[ndups[j]][0].m_callsign)
1409  m_channelInfos[ndups[j]].push_back(channels[i]);
1410  }
1411 
1412  const uint_list_t &cdups = callsign_to_index_map[channels[i].m_callsign];
1413  for (size_t j = 0; j < cdups.size(); ++j)
1414  {
1415  if (channels[i].m_chanid != m_channelInfos[cdups[j]][0].m_chanid)
1416  m_channelInfos[cdups[j]].push_back(channels[i]);
1417  }
1418  }
1419 
1420  if (gotostartchannel)
1421  {
1422  int ch = FindChannel(m_startChanID, m_startChanNum, false);
1423  m_currentStartChannel = (uint) max(0, ch);
1424  }
1425 
1426  if (m_channelInfos.empty())
1427  {
1428  LOG(VB_GENERAL, LOG_ERR, "GuideGrid: "
1429  "\n\t\t\tYou don't have any channels defined in the database."
1430  "\n\t\t\tGuide grid will have nothing to show you.");
1431  }
1432 }
1433 
1434 int GuideGrid::FindChannel(uint chanid, const QString &channum,
1435  bool exact) const
1436 {
1437  static QMutex chanSepRegExpLock;
1438  static QRegExp chanSepRegExp(ChannelUtil::kATSCSeparators);
1439 
1440  // first check chanid
1441  uint i = (chanid) ? 0 : GetChannelCount();
1442  for (; i < GetChannelCount(); ++i)
1443  {
1444  if (m_channelInfos[i][0].m_chanid == chanid)
1445  return i;
1446  }
1447 
1448  // then check for chanid in duplicates
1449  i = (chanid) ? 0 : GetChannelCount();
1450  for (; i < GetChannelCount(); ++i)
1451  {
1452  for (size_t j = 1; j < m_channelInfos[i].size(); ++j)
1453  {
1454  if (m_channelInfos[i][j].m_chanid == chanid)
1455  return i;
1456  }
1457  }
1458 
1459  // then check channum, first only
1460  i = (channum.isEmpty()) ? GetChannelCount() : 0;
1461  for (; i < GetChannelCount(); ++i)
1462  {
1463  if (m_channelInfos[i][0].m_channum == channum)
1464  return i;
1465  }
1466 
1467  // then check channum duplicates
1468  i = (channum.isEmpty()) ? GetChannelCount() : 0;
1469  for (; i < GetChannelCount(); ++i)
1470  {
1471  for (size_t j = 1; j < m_channelInfos[i].size(); ++j)
1472  {
1473  if (m_channelInfos[i][j].m_channum == channum)
1474  return i;
1475  }
1476  }
1477 
1478  if (exact || channum.isEmpty())
1479  return -1;
1480 
1481  ChannelInfoList list;
1482  QVector<int> idxList;
1483  for (i = 0; i < GetChannelCount(); ++i)
1484  {
1485  for (size_t j = 0; j < m_channelInfos[i].size(); ++j)
1486  {
1487  list.push_back(m_channelInfos[i][j]);
1488  idxList.push_back(i);
1489  }
1490  }
1491  int result = ChannelUtil::GetNearestChannel(list, channum);
1492  if (result >= 0)
1493  result = idxList[result];
1494  return result;
1495 }
1496 
1498 {
1499  m_timeList->Reset();
1500 
1501  QDateTime starttime = m_currentStartTime;
1502 
1504  m_lastTime = m_firstTime.addSecs(m_timeCount * 60 * 4);
1505 
1506  for (int x = 0; x < m_timeCount; ++x)
1507  {
1508  int mins = starttime.time().minute();
1509  mins = 5 * (mins / 5);
1510  if (mins % 30 == 0)
1511  {
1512  QString timeStr = MythDate::toString(starttime, MythDate::kTime);
1513 
1514  InfoMap infomap;
1515  infomap["starttime"] = timeStr;
1516 
1517  QDateTime endtime = starttime.addSecs(60 * 30);
1518 
1519  infomap["endtime"] = MythDate::toString(endtime, MythDate::kTime);
1520 
1521  MythUIButtonListItem *item =
1522  new MythUIButtonListItem(m_timeList, timeStr);
1523 
1524  item->SetTextFromMap(infomap);
1525  }
1526 
1527  starttime = starttime.addSecs(5 * 60);
1528  }
1529  m_currentEndTime = starttime;
1530 }
1531 
1532 void GuideGrid::fillProgramInfos(bool useExistingData)
1533 {
1534  fillProgramRowInfos(-1, useExistingData);
1535 }
1536 
1538 {
1539  ProgramList *proglist = new ProgramList();
1540 
1541  if (proglist)
1542  {
1543  MSqlBindings bindings;
1544  QString querystr = "WHERE program.chanid = :CHANID "
1545  " AND program.endtime >= :STARTTS "
1546  " AND program.starttime <= :ENDTS "
1547  " AND program.starttime >= :STARTLIMITTS "
1548  " AND program.manualid = 0 ";
1549  QDateTime starttime = m_currentStartTime.addSecs(0 - m_currentStartTime.time().second());
1550  bindings[":CHANID"] = GetChannelInfo(chanNum)->m_chanid;
1551  bindings[":STARTTS"] = starttime;
1552  bindings[":STARTLIMITTS"] = starttime.addDays(-1);
1553  bindings[":ENDTS"] = m_currentEndTime.addSecs(0 - m_currentEndTime.time().second());
1554 
1555  LoadFromProgram(*proglist, querystr, bindings, m_recList);
1556  }
1557 
1558  return proglist;
1559 }
1560 
1561 void GuideGrid::fillProgramRowInfos(int firstRow, bool useExistingData)
1562 {
1563  bool allRows = false;
1564  unsigned int numRows = 1;
1565  if (firstRow < 0)
1566  {
1567  firstRow = 0;
1568  allRows = true;
1569  numRows = min((unsigned int)m_channelInfos.size(),
1570  (unsigned int)m_guideGrid->getChannelCount());
1571  }
1572  QVector<int> chanNums;
1573  QVector<ProgramList*> proglists;
1574 
1575  for (unsigned int i = 0; i < numRows; ++i)
1576  {
1577  unsigned int row = i + firstRow;
1578  // never divide by zero..
1580  return;
1581 
1582  for (int x = 0; x < m_timeCount; ++x)
1583  {
1584  m_programInfos[row][x] = nullptr;
1585  }
1586 
1587  if (m_channelInfos.empty())
1588  return;
1589 
1590  int chanNum = row + m_currentStartChannel;
1591  if (chanNum >= (int) m_channelInfos.size())
1592  chanNum -= (int) m_channelInfos.size();
1593  if (chanNum >= (int) m_channelInfos.size())
1594  return;
1595 
1596  if (chanNum < 0)
1597  chanNum = 0;
1598 
1599  ProgramList *proglist = nullptr;
1600  if (useExistingData)
1601  proglist = CopyProglist(m_programs[row]);
1602  chanNums.push_back(chanNum);
1603  proglists.push_back(proglist);
1604  }
1605  if (allRows)
1606  {
1607  for (unsigned int i = numRows;
1608  i < (unsigned int) m_guideGrid->getChannelCount(); ++i)
1609  {
1610  delete m_programs[i];
1611  m_programs[i] = nullptr;
1612  m_guideGrid->ResetRow(i);
1613  }
1614  }
1615 
1617 
1618  GuideStatus gs(firstRow, chanNums.size(), chanNums,
1623  GuideUpdateProgramRow *updater =
1624  new GuideUpdateProgramRow(this, gs, proglists);
1625  m_threadPool.start(new GuideHelper(this, updater), "GuideHelper");
1626 }
1627 
1629  const QDateTime& start,
1630  ProgramList *proglist)
1631 {
1632  if (row < 0 || row >= m_channelCount ||
1633  start != m_currentStartTime)
1634  {
1635  delete proglist;
1636  return;
1637  }
1638 
1639  QDateTime ts = m_currentStartTime;
1640 
1641  QDateTime tnow = MythDate::current();
1642  int progPast = 0;
1643  if (tnow > m_currentEndTime)
1644  progPast = 100;
1645  else if (tnow < m_currentStartTime)
1646  progPast = 0;
1647  else
1648  {
1649  int played = m_currentStartTime.secsTo(tnow);
1650  int length = m_currentStartTime.secsTo(m_currentEndTime);
1651  if (length)
1652  progPast = played * 100 / length;
1653  }
1654 
1655  m_progPast = progPast;
1656 
1657  ProgramList::iterator program = proglist->begin();
1658  vector<ProgramInfo*> unknownlist;
1659  bool unknown = false;
1660  ProgramInfo *proginfo = nullptr;
1661  for (int x = 0; x < m_timeCount; ++x)
1662  {
1663  if (program != proglist->end() &&
1664  (ts >= (*program)->GetScheduledEndTime()))
1665  {
1666  ++program;
1667  }
1668 
1669  if ((program == proglist->end()) ||
1670  (ts < (*program)->GetScheduledStartTime()))
1671  {
1672  if (unknown)
1673  {
1674  if (proginfo)
1675  {
1676  proginfo->m_spread++;
1677  proginfo->SetScheduledEndTime(proginfo->GetScheduledEndTime().addSecs(5 * 60));
1678  }
1679  }
1680  else
1681  {
1682  proginfo = new ProgramInfo(kUnknownTitle,
1683  GuideGrid::tr("Unknown", "Unknown program title"),
1684  ts, ts.addSecs(5*60));
1685  unknownlist.push_back(proginfo);
1686  proginfo->m_startCol = x;
1687  proginfo->m_spread = 1;
1688  unknown = true;
1689  }
1690  }
1691  else
1692  {
1693  if (proginfo && proginfo == *program)
1694  {
1695  proginfo->m_spread++;
1696  }
1697  else
1698  {
1699  proginfo = *program;
1700  if (proginfo)
1701  {
1702  proginfo->m_startCol = x;
1703  proginfo->m_spread = 1;
1704  unknown = false;
1705  }
1706  }
1707  }
1708  m_programInfos[row][x] = proginfo;
1709  ts = ts.addSecs(5 * 60);
1710  }
1711 
1712  vector<ProgramInfo*>::iterator it = unknownlist.begin();
1713  for (; it != unknownlist.end(); ++it)
1714  proglist->push_back(*it);
1715 
1716  MythRect programRect = m_gg_programRect;
1717 
1719  double ydifference = 0.0, xdifference = 0.0;
1720 
1721  if (m_verticalLayout)
1722  {
1723  ydifference = programRect.width() /
1724  (double) m_gg_channelCount;
1725  xdifference = programRect.height() /
1726  (double) m_timeCount;
1727  }
1728  else
1729  {
1730  ydifference = programRect.height() /
1731  (double) m_gg_channelCount;
1732  xdifference = programRect.width() /
1733  (double) m_timeCount;
1734  }
1735 
1736  int arrow = GridTimeNormal;
1737  int cnt = 0;
1738  int spread = 1;
1739  QDateTime lastprog;
1740  QRect tempRect;
1741  bool isCurrent = false;
1742 
1743  for (int x = 0; x < m_timeCount; ++x)
1744  {
1745  ProgramInfo *pginfo = m_programInfos[row][x];
1746  if (!pginfo)
1747  continue;
1748 
1749  spread = 1;
1750  if (pginfo->GetScheduledStartTime() != lastprog)
1751  {
1752  arrow = GridTimeNormal;
1753  if (pginfo->GetScheduledStartTime() < m_firstTime.addSecs(-300))
1754  arrow |= GridTimeStartsBefore;
1755  if (pginfo->GetScheduledEndTime() > m_lastTime.addSecs(2100))
1756  arrow |= GridTimeEndsAfter;
1757 
1758  if (pginfo->m_spread != -1)
1759  {
1760  spread = pginfo->m_spread;
1761  }
1762  else
1763  {
1764  for (int z = x + 1; z < m_timeCount; ++z)
1765  {
1766  ProgramInfo *test = m_programInfos[row][z];
1767  if (test && (test->GetScheduledStartTime() ==
1768  pginfo->GetScheduledStartTime()))
1769  spread++;
1770  }
1771  pginfo->m_spread = spread;
1772  pginfo->m_startCol = x;
1773 
1774  for (int z = x + 1; z < x + spread; ++z)
1775  {
1776  ProgramInfo *test = m_programInfos[row][z];
1777  if (test)
1778  {
1779  test->m_spread = spread;
1780  test->m_startCol = x;
1781  }
1782  }
1783  }
1784 
1785  if (m_verticalLayout)
1786  {
1787  tempRect = QRect((int)(row * ydifference),
1788  (int)(x * xdifference),
1789  (int)(ydifference),
1790  (int)(xdifference * pginfo->m_spread));
1791  }
1792  else
1793  {
1794  tempRect = QRect((int)(x * xdifference),
1795  (int)(row * ydifference),
1796  (int)(xdifference * pginfo->m_spread),
1797  (int)ydifference);
1798  }
1799 
1800  // snap to right edge for last entry.
1801  if (tempRect.right() + 2 >= programRect.width())
1802  tempRect.setRight(programRect.width());
1803  if (tempRect.bottom() + 2 >= programRect.bottom())
1804  tempRect.setBottom(programRect.bottom());
1805 
1806  isCurrent = m_currentRow == row && (m_currentCol >= x) &&
1807  (m_currentCol < (x + spread));
1808 
1809  int recFlag;
1810  switch (pginfo->GetRecordingRuleType())
1811  {
1812  case kSingleRecord:
1813  recFlag = 1;
1814  break;
1815  case kDailyRecord:
1816  recFlag = 2;
1817  break;
1818  case kAllRecord:
1819  recFlag = 4;
1820  break;
1821  case kWeeklyRecord:
1822  recFlag = 5;
1823  break;
1824  case kOneRecord:
1825  recFlag = 6;
1826  break;
1827  case kOverrideRecord:
1828  case kDontRecord:
1829  recFlag = 7;
1830  break;
1831  case kNotRecording:
1832  default:
1833  recFlag = 0;
1834  break;
1835  }
1836 
1837  int recStat;
1838  if (pginfo->GetRecordingStatus() == RecStatus::Conflict ||
1840  recStat = 2;
1841  else if (pginfo->GetRecordingStatus() <= RecStatus::WillRecord)
1842  recStat = 1;
1843  else
1844  recStat = 0;
1845 
1846  QString title = (pginfo->GetTitle() == kUnknownTitle) ?
1847  GuideGrid::tr("Unknown", "Unknown program title") :
1848  pginfo->GetTitle();
1849  m_result.push_back(GuideUIElement(
1850  row, cnt, tempRect, title,
1851  pginfo->GetCategory(), arrow, recFlag,
1852  recStat, isCurrent));
1853 
1854  cnt++;
1855  }
1856 
1857  lastprog = pginfo->GetScheduledStartTime();
1858  }
1859 }
1860 
1861 void GuideGrid::customEvent(QEvent *event)
1862 {
1863  if (event->type() == MythEvent::MythEventMessage)
1864  {
1865  MythEvent *me = static_cast<MythEvent *>(event);
1866  const QString& message = me->Message();
1867 
1868  if (message == "SCHEDULE_CHANGE")
1869  {
1870  GuideHelper::Wait(this);
1872  fillProgramInfos();
1873  }
1874  else if (message == "STOP_VIDEO_REFRESH_TIMER")
1875  {
1877  }
1878  else if (message == "START_VIDEO_REFRESH_TIMER")
1879  {
1880  m_previewVideoRefreshTimer->start(66);
1881  }
1882  }
1883  else if (event->type() == DialogCompletionEvent::kEventType)
1884  {
1886 
1887  QString resultid = dce->GetId();
1888  QString resulttext = dce->GetResultText();
1889  int buttonnum = dce->GetResult();
1890 
1891  if (resultid == "deleterule")
1892  {
1893  RecordingRule *record =
1894  dce->GetData().value<RecordingRule *>();
1895  if (record)
1896  {
1897  if ((buttonnum > 0) && !record->Delete())
1898  LOG(VB_GENERAL, LOG_ERR, "Failed to delete recording rule");
1899  delete record;
1900  }
1901  }
1902  // Test for this here because it can come from
1903  // different menus.
1904  else if (resulttext == tr("Watch This Channel"))
1905  {
1906  ChannelInfoList selection = GetSelection();
1907  if (SelectionIsTunable(selection))
1908  TV::StartTV(nullptr, kStartTVNoFlags, selection);
1909  }
1910  else if (resultid == "guidemenu")
1911  {
1912  if (resulttext == tr("Record This"))
1913  {
1914  QuickRecord();
1915  }
1916  else if (resulttext == tr("Change to Channel"))
1917  {
1918  enter();
1919  }
1920  else if (resulttext == tr("Program Details"))
1921  {
1922  ShowDetails();
1923  }
1924  else if (resulttext == tr("Reverse Channel Order"))
1925  {
1927  generateListings();
1928  updateChannels();
1929  }
1930  else if (resulttext == tr("Channel Search"))
1931  {
1933  }
1934  else if (resulttext == tr("Add To Channel Group"))
1935  {
1936  if (m_changrpid == -1)
1937  ChannelGroupMenu(0);
1938  }
1939  else if (resulttext == tr("Remove from Channel Group"))
1940  {
1942  }
1943  else if (resulttext == tr("Choose Channel Group"))
1944  {
1945  ChannelGroupMenu(1);
1946  }
1947  else if (resulttext == tr("Recording Options"))
1948  {
1950  }
1951  else if (resulttext == tr("Jump to Time"))
1952  {
1953  ShowJumpToTime();
1954  }
1955  }
1956  else if (resultid == "recmenu")
1957  {
1958  if (resulttext == tr("Edit Recording Status"))
1959  {
1960  EditRecording();
1961  }
1962  else if (resulttext == tr("Edit Schedule"))
1963  {
1964  EditScheduled();
1965  }
1966  else if (resulttext == tr("Show Upcoming"))
1967  {
1968  ShowUpcoming();
1969  }
1970  else if (resulttext == tr("Previously Recorded"))
1971  {
1972  ShowPrevious();
1973  }
1974  else if (resulttext == tr("Custom Edit"))
1975  {
1976  EditCustom();
1977  }
1978  else if (resulttext == tr("Delete Rule"))
1979  {
1980  deleteRule();
1981  }
1982 
1983  }
1984  else if (resultid == "channelgrouptogglemenu")
1985  {
1986  int changroupid;
1987  changroupid = ChannelGroup::GetChannelGroupId(resulttext);
1988 
1989  if (changroupid > 0)
1990  toggleChannelFavorite(changroupid);
1991  }
1992  else if (resultid == "channelgroupmenu")
1993  {
1994  if (buttonnum >= 0)
1995  {
1996  int changroupid;
1997 
1998  if (resulttext == QObject::tr("All Channels"))
1999  changroupid = -1;
2000  else
2001  changroupid = ChannelGroup::GetChannelGroupId(resulttext);
2002 
2003  m_changrpid = changroupid;
2004  generateListings();
2005  updateChannels();
2006  updateInfo();
2007 
2008  QString changrpname;
2010 
2011  if (m_changroupname)
2012  m_changroupname->SetText(changrpname);
2013  }
2014  }
2015  else if (resultid == "jumptotime")
2016  {
2017  QDateTime datetime = dce->GetData().toDateTime();
2018  moveToTime(datetime);
2019  }
2020  else
2022  }
2023  else if (event->type() == UpdateGuideEvent::kEventType)
2024  {
2025  UpdateGuideEvent *uge = static_cast<UpdateGuideEvent*>(event);
2026  if (uge->m_updater)
2027  {
2028  uge->m_updater->ExecuteUI();
2029  delete uge->m_updater;
2030  uge->m_updater = nullptr;
2031  }
2032  }
2033 }
2034 
2036 {
2037  if (m_dateText)
2039  if (m_longdateText)
2042 }
2043 
2044 void GuideGrid::updateProgramsUI(unsigned int firstRow, unsigned int numRows,
2045  int progPast,
2046  const QVector<ProgramList*> &proglists,
2047  const ProgInfoGuideArray &programInfos,
2048  const QLinkedList<GuideUIElement> &elements)
2049 {
2050  for (unsigned int i = 0; i < numRows; ++i)
2051  {
2052  unsigned int row = i + firstRow;
2053  m_guideGrid->ResetRow(row);
2054  if (m_programs[row] != proglists[i])
2055  {
2056  delete m_programs[row];
2057  m_programs[row] = proglists[i];
2058  }
2059  }
2060  m_guideGrid->SetProgPast(progPast);
2061  for (QLinkedList<GuideUIElement>::const_iterator it = elements.begin();
2062  it != elements.end(); ++it)
2063  {
2064  const GuideUIElement &r = *it;
2065  m_guideGrid->SetProgramInfo(r.m_row, r.m_col, r.m_area, r.m_title,
2066  r.m_category, r.m_arrow, r.m_recType,
2067  r.m_recStat, r.m_selected);
2068  }
2069  for (unsigned int i = firstRow; i < firstRow + numRows; ++i)
2070  {
2071  for (int j = 0; j < MAX_DISPLAY_TIMES; ++j)
2072  m_programInfos[i][j] = programInfos[i][j];
2073  if (i == (unsigned int)m_currentRow)
2074  updateInfo();
2075  }
2077 }
2078 
2080 {
2081  GuideUpdateChannels *updater =
2083  m_threadPool.start(new GuideHelper(this, updater), "GuideHelper");
2084 }
2085 
2086 void GuideGrid::updateChannelsNonUI(QVector<ChannelInfo *> &chinfos,
2087  QVector<bool> &unavailables)
2088 {
2090 
2091  for (unsigned int y = 0; (y < (unsigned int)m_channelCount) && chinfo; ++y)
2092  {
2093  unsigned int chanNumber = y + m_currentStartChannel;
2094  if (chanNumber >= m_channelInfos.size())
2095  chanNumber -= m_channelInfos.size();
2096  if (chanNumber >= m_channelInfos.size())
2097  break;
2098 
2099  chinfo = GetChannelInfo(chanNumber);
2100 
2101  bool unavailable = false, try_alt = false;
2102 
2103  if (m_player)
2104  {
2106  -1, __FILE__, __LINE__);
2107  if (ctx && chinfo)
2108  try_alt = !m_player->IsTunable(ctx, chinfo->m_chanid);
2109  m_player->ReturnPlayerLock(ctx);
2110  }
2111 
2112  if (try_alt)
2113  {
2114  unavailable = true;
2115 
2116  // Try alternates with same channum if applicable
2117  uint alt = GetAlternateChannelIndex(chanNumber, true);
2118  if (alt != m_channelInfoIdx[chanNumber])
2119  {
2120  unavailable = false;
2121  m_channelInfoIdx[chanNumber] = alt;
2122  chinfo = GetChannelInfo(chanNumber);
2123  }
2124 
2125  // Try alternates with different channum if applicable
2126  if (unavailable && chinfo &&
2127  !GetProgramList(chinfo->m_chanid).empty())
2128  {
2129  alt = GetAlternateChannelIndex(chanNumber, false);
2130  unavailable = (alt == m_channelInfoIdx[chanNumber]);
2131  }
2132  }
2133  chinfos.push_back(chinfo);
2134  unavailables.push_back(unavailable);
2135  }
2136 }
2137 
2138 void GuideGrid::updateChannelsUI(const QVector<ChannelInfo *> &chinfos,
2139  const QVector<bool> &unavailables)
2140 {
2141  m_channelList->Reset();
2142  for (int i = 0; i < chinfos.size(); ++i)
2143  {
2144  ChannelInfo *chinfo = chinfos[i];
2145  bool unavailable = unavailables[i];
2146  MythUIButtonListItem *item =
2148  chinfo ? chinfo->GetFormatted(ChannelInfo::kChannelShort) : QString());
2149 
2150  QString state = "available";
2151  if (unavailable)
2152  state = (m_changrpid == -1) ? "unavailable" : "favunavailable";
2153  else
2154  state = (m_changrpid == -1) ? "available" : "favourite";
2155 
2156  item->SetFontState(state);
2157  item->DisplayState(state, "chanstatus");
2158 
2159  if (chinfo)
2160  {
2161  InfoMap infomap;
2162  chinfo->ToMap(infomap);
2163  item->SetTextFromMap(infomap);
2164 
2165  if (!chinfo->m_icon.isEmpty())
2166  {
2167  QString iconurl =
2168  gCoreContext->GetMasterHostPrefix("ChannelIcons",
2169  chinfo->m_icon);
2170  item->SetImage(iconurl, "channelicon");
2171  }
2172  }
2173  }
2175 }
2176 
2178 {
2179  if (m_currentRow < 0 || m_currentCol < 0)
2180  return;
2181 
2183  if (!pginfo)
2184  return;
2185 
2186  InfoMap infoMap;
2187 
2188  int chanNum = m_currentRow + m_currentStartChannel;
2189  if (chanNum >= (int)m_channelInfos.size())
2190  chanNum -= (int)m_channelInfos.size();
2191  if (chanNum >= (int)m_channelInfos.size())
2192  return;
2193  if (chanNum < 0)
2194  chanNum = 0;
2195 
2196  ChannelInfo *chinfo = GetChannelInfo(chanNum);
2197 
2198  if (m_channelImage)
2199  {
2200  m_channelImage->Reset();
2201  if (!chinfo->m_icon.isEmpty())
2202  {
2203  QString iconurl = gCoreContext->GetMasterHostPrefix("ChannelIcons",
2204  chinfo->m_icon);
2205 
2206  m_channelImage->SetFilename(iconurl);
2207  m_channelImage->Load();
2208  }
2209  }
2210 
2211  chinfo->ToMap(infoMap);
2212  pginfo->ToMap(infoMap);
2213  // HACK - This should be done in ProgramInfo, but that needs more careful
2214  // review since it may have unintended consequences so we're doing it here
2215  // for now
2216  if (infoMap["title"] == kUnknownTitle)
2217  {
2218  infoMap["title"] = tr("Unknown", "Unknown program title");
2219  infoMap["titlesubtitle"] = tr("Unknown", "Unknown program title");
2220  }
2221 
2222  SetTextFromMap(infoMap);
2223 
2224  MythUIStateType *ratingState = dynamic_cast<MythUIStateType*>
2225  (GetChild("ratingstate"));
2226  if (ratingState)
2227  {
2228  QString rating = QString::number(pginfo->GetStars(10));
2229  ratingState->DisplayState(rating);
2230  }
2232 }
2233 
2235 {
2236  int oldchangrpid = m_changrpid;
2237 
2239 
2240  if (oldchangrpid != m_changrpid)
2241  generateListings();
2242 
2243  updateChannels();
2244  updateInfo();
2245 
2246  QString changrpname = ChannelGroup::GetChannelGroupName(m_changrpid);
2247 
2248  if (m_changroupname)
2249  m_changroupname->SetText(changrpname);
2250 }
2251 
2253 {
2255  m_currentRow = 0;
2256 
2257  int maxchannel = 0;
2258  fillChannelInfos();
2259  maxchannel = max((int)GetChannelCount() - 1, 0);
2260  m_channelCount = min(m_guideGrid->getChannelCount(), maxchannel + 1);
2261 
2263  fillProgramInfos();
2264 }
2265 
2267 {
2268  ChannelGroupList channels = ChannelGroup::GetChannelGroups(mode == 0);
2269 
2270  if (channels.empty())
2271  {
2272  QString message = tr("You don't have any channel groups defined");
2273 
2274  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2275 
2276  MythConfirmationDialog *okPopup = new MythConfirmationDialog(popupStack,
2277  message, false);
2278  if (okPopup->Create())
2279  popupStack->AddScreen(okPopup);
2280  else
2281  delete okPopup;
2282 
2283  return;
2284  }
2285 
2286  QString label = tr("Select Channel Group");
2287 
2288  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2289  MythDialogBox *menuPopup = new MythDialogBox(label, popupStack, "menuPopup");
2290 
2291  if (menuPopup->Create())
2292  {
2293  if (mode == 0)
2294  {
2295  // add channel to group menu
2296  menuPopup->SetReturnEvent(this, "channelgrouptogglemenu");
2297  }
2298  else
2299  {
2300  // switch to channel group menu
2301  menuPopup->SetReturnEvent(this, "channelgroupmenu");
2302  menuPopup->AddButton(QObject::tr("All Channels"));
2303  }
2304 
2305  for (size_t i = 0; i < channels.size(); ++i)
2306  {
2307  menuPopup->AddButton(channels[i].m_name);
2308  }
2309 
2310  popupStack->AddScreen(menuPopup);
2311  }
2312  else
2313  {
2314  delete menuPopup;
2315  }
2316 }
2317 
2319 {
2320  MSqlQuery query(MSqlQuery::InitCon());
2321 
2322  if (grpid == -1)
2323  {
2324  if (m_changrpid == -1)
2325  return;
2326  grpid = m_changrpid;
2327  }
2328 
2329  // Get current channel id, and make sure it exists...
2330  int chanNum = m_currentRow + m_currentStartChannel;
2331  if (chanNum >= (int)m_channelInfos.size())
2332  chanNum -= (int)m_channelInfos.size();
2333  if (chanNum >= (int)m_channelInfos.size())
2334  return;
2335  if (chanNum < 0)
2336  chanNum = 0;
2337 
2338  ChannelInfo *ch = GetChannelInfo(chanNum);
2339  uint chanid = ch->m_chanid;
2340 
2341  if (m_changrpid == -1)
2342  // If currently viewing all channels, allow to add only not delete
2343  ChannelGroup::ToggleChannel(chanid, grpid, false);
2344  else
2345  // Only allow delete if viewing the favorite group in question
2346  ChannelGroup::ToggleChannel(chanid, grpid, true);
2347 
2348  //regenerate the list of non empty group in case it did change
2350 
2351  // If viewing favorites, refresh because a channel was removed
2352  if (m_changrpid != -1)
2353  {
2354  generateListings();
2355  updateChannels();
2356  updateInfo();
2357  }
2358 }
2359 
2361 {
2363 
2364  if (!test)
2365  {
2367  return;
2368  }
2369 
2370  int startCol = test->m_startCol;
2371  m_currentCol = startCol - 1;
2372 
2373  if (m_currentCol < 0)
2374  {
2375  m_currentCol = 0;
2377  }
2378  else
2379  {
2381  }
2382 }
2383 
2385 {
2387 
2388  if (!test)
2389  {
2391  return;
2392  }
2393 
2394  int spread = test->m_spread;
2395  int startCol = test->m_startCol;
2396 
2397  m_currentCol = startCol + spread;
2398 
2399  if (m_currentCol > m_timeCount - 1)
2400  {
2401  m_currentCol = m_timeCount - 1;
2403  }
2404  else
2405  {
2407  }
2408 }
2409 
2411 {
2412  m_currentRow++;
2413 
2414  if (m_currentRow > m_channelCount - 1)
2415  {
2418  }
2419  else
2420  {
2422  }
2423 }
2424 
2426 {
2427  m_currentRow--;
2428 
2429  if (m_currentRow < 0)
2430  {
2431  m_currentRow = 0;
2433  }
2434  else
2435  {
2437  }
2438 }
2439 
2441 {
2442  switch (movement)
2443  {
2444  case kScrollLeft :
2445  m_currentStartTime = m_currentStartTime.addSecs(-30 * 60);
2446  break;
2447  case kScrollRight :
2448  m_currentStartTime = m_currentStartTime.addSecs(30 * 60);
2449  break;
2450  case kPageLeft :
2451  m_currentStartTime = m_currentStartTime.addSecs(-5 * 60 * m_timeCount);
2452  break;
2453  case kPageRight :
2455  break;
2456  case kDayLeft :
2457  m_currentStartTime = m_currentStartTime.addSecs(-24 * 60 * 60);
2458  break;
2459  case kDayRight :
2460  m_currentStartTime = m_currentStartTime.addSecs(24 * 60 * 60);
2461  break;
2462  default :
2463  break;
2464  }
2465 
2466  fillTimeInfos();
2467  fillProgramInfos();
2468  updateDateText();
2469 }
2470 
2472 {
2473  switch (movement)
2474  {
2475  case kScrollDown :
2477  break;
2478  case kScrollUp :
2480  break;
2481  case kPageDown :
2483  break;
2484  case kPageUp :
2486  break;
2487  default :
2488  break;
2489  }
2490 
2491  fillProgramInfos();
2492  updateChannels();
2493 }
2494 
2495 void GuideGrid::moveToTime(const QDateTime& datetime)
2496 {
2497  if (!datetime.isValid())
2498  return;
2499 
2500  m_currentStartTime = datetime;
2501 
2502  fillTimeInfos();
2503  fillProgramInfos();
2504  updateDateText();
2505 }
2506 
2507 void GuideGrid::setStartChannel(int newStartChannel)
2508 {
2509  if (newStartChannel < 0)
2510  m_currentStartChannel = newStartChannel + GetChannelCount();
2511  else if (newStartChannel >= (int) GetChannelCount())
2512  m_currentStartChannel = newStartChannel - GetChannelCount();
2513  else
2514  m_currentStartChannel = newStartChannel;
2515 }
2516 
2518 {
2519  if (m_allowFinder)
2521 }
2522 
2524 {
2525  if (!m_player)
2526  return;
2527 
2528  m_updateTimer->stop();
2529 
2530  channelUpdate();
2531 
2532  // Don't perform transition effects when guide is being used during playback
2533  GetScreenStack()->PopScreen(this, false);
2534 
2535  epgIsVisibleCond.wakeAll();
2536 }
2537 
2539 {
2540  // HACK: Do not allow exit if we have a popup menu open, not convinced
2541  // that this is the right solution
2542  if (GetMythMainWindow()->GetStack("popup stack")->TotalScreens() > 0)
2543  return;
2544 
2545  m_updateTimer->stop();
2546 
2547  // don't fade the screen if we are returning to the player
2548  if (m_player)
2549  GetScreenStack()->PopScreen(this, false);
2550  else
2551  GetScreenStack()->PopScreen(this, true);
2552 
2553  epgIsVisibleCond.wakeAll();
2554 }
2555 
2557 {
2559 
2560  if (!pginfo || !pginfo->GetRecordingRuleID())
2561  return;
2562 
2563  RecordingRule *record = new RecordingRule();
2564  if (!record->LoadByProgram(pginfo))
2565  {
2566  delete record;
2567  return;
2568  }
2569 
2570  QString message = tr("Delete '%1' %2 rule?").arg(record->m_title)
2571  .arg(toString(pginfo->GetRecordingRuleType()));
2572 
2573  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2574 
2575  MythConfirmationDialog *okPopup = new MythConfirmationDialog(popupStack,
2576  message, true);
2577 
2578  okPopup->SetReturnEvent(this, "deleterule");
2579  okPopup->SetData(qVariantFromValue(record));
2580 
2581  if (okPopup->Create())
2582  popupStack->AddScreen(okPopup);
2583  else
2584  delete okPopup;
2585 }
2586 
2588 {
2589  if (!m_player)
2590  return;
2591 
2592  ChannelInfoList sel = GetSelection();
2593 
2594  if (!sel.empty())
2595  {
2596  PlayerContext *ctx = m_player->GetPlayerReadLock(-1, __FILE__, __LINE__);
2597  m_player->ChangeChannel(ctx, sel);
2598  m_player->ReturnPlayerLock(ctx);
2599  }
2600 }
2601 
2603 {
2604  if (m_player)
2605  {
2606  PlayerContext *ctx = m_player->GetPlayerReadLock(-1, __FILE__, __LINE__);
2607  m_player->ChangeVolume(ctx, up);
2608  m_player->ReturnPlayerLock(ctx);
2609  }
2610 }
2611 
2612 void GuideGrid::toggleMute(const bool muteIndividualChannels)
2613 {
2614  if (m_player)
2615  {
2616  PlayerContext *ctx = m_player->GetPlayerReadLock(-1, __FILE__, __LINE__);
2617  m_player->ToggleMute(ctx, muteIndividualChannels);
2618  m_player->ReturnPlayerLock(ctx);
2619  }
2620 }
2621 
2622 void GuideGrid::GoTo(int start, int cur_row)
2623 {
2624  setStartChannel(start);
2625  m_currentRow = cur_row % m_channelCount;
2626  updateChannels();
2627  fillProgramInfos();
2629 }
2630 
2632 {
2633  QString txt;
2634  {
2635  QMutexLocker locker(&m_jumpToChannelLock);
2636  if (m_jumpToChannel)
2637  txt = m_jumpToChannel->GetEntry();
2638  }
2639 
2640  if (txt.isEmpty())
2641  return;
2642 
2643  if (m_jumpToText)
2644  m_jumpToText->SetText(txt);
2645 }
2646 
2648 {
2649  QMutexLocker locker(&m_jumpToChannelLock);
2650  m_jumpToChannel = ptr;
2651 
2652  if (!m_jumpToChannel)
2653  {
2654  if (m_jumpToText)
2655  m_jumpToText->Reset();
2656 
2657  updateDateText();
2658  }
2659 }
2660 
2662 {
2663  GetMythMainWindow()->GetPaintWindow()->clearMask();
2664 }
2665 
2667 {
2668  MythEvent *me = new MythEvent("STOP_VIDEO_REFRESH_TIMER");
2669  qApp->postEvent(this, me);
2670 
2672  if (!m_usingNullVideo)
2673  {
2674  QRegion r1 = QRegion(m_Area);
2675  QRegion r2 = QRegion(m_videoRect);
2676  GetMythMainWindow()->GetPaintWindow()->setMask(r1.xored(r2));
2678  }
2679  else
2680  {
2681  me = new MythEvent("START_VIDEO_REFRESH_TIMER");
2682  qApp->postEvent(this, me);
2683  }
2684 }
2685 
2687 {
2688  if (m_player && m_usingNullVideo)
2689  {
2691  }
2692 }
2693 
2695 {
2696  if (m_player)
2697  HideTVWindow();
2698 
2700 }
2701 
2703 {
2704  if (m_player)
2705  EmbedTVWindow();
2706 
2708 }
2709 
2711 {
2712  QString message = tr("Jump to a specific date and time in the guide");
2715 
2716  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2717  MythTimeInputDialog *timedlg = new MythTimeInputDialog(popupStack, message,
2718  flags);
2719 
2720  if (timedlg->Create())
2721  {
2722  timedlg->SetReturnEvent(this, "jumptotime");
2723  popupStack->AddScreen(timedlg);
2724  }
2725  else
2726  delete timedlg;
2727 }
This widget is used for grouping other widgets for display when a particular named state is called.
void setMaxThreadCount(int maxThreadCount)
QDateTime GetCurrentStartTime(void) const
Definition: guidegrid.h:134
virtual void aboutToShow(void)
bool m_allowFinder
Definition: guidegrid.h:239
float GetStars(void) const
Definition: programinfo.h:434
MythUIImage * m_channelImage
Definition: guidegrid.h:293
bool ExecuteNonUI(void) override
Definition: guidegrid.cpp:274
uint m_startChanID
Definition: guidegrid.h:251
A narrow purpose widget used to show television programs and the timeslots they occupy on channels.
MythScreenStack * GetScreenStack() const
static QMap< GuideGrid *, uint > s_loading
Definition: guidegrid.cpp:412
JumpToChannelListener * m_listener
Definition: guidegrid.h:70
QString m_startChanNum
Definition: guidegrid.h:252
int m_previous_start_channel_index
Definition: guidegrid.h:72
void ToMap(InfoMap &infoMap)
void cursorLeft()
Definition: guidegrid.cpp:2360
static QWaitCondition s_wait
Definition: guidegrid.cpp:411
void cursorDown()
Definition: guidegrid.cpp:2410
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
Definition: tv.h:63
bool StartEmbedding(const QRect &)
Definition: tv_play.cpp:8534
void push_back(T info)
virtual void ToMap(InfoMap &progMap, bool showrerecord=false, uint star_range=10) const
Converts ProgramInfo into QString QHash containing each field in ProgramInfo converted into localized...
bool LoadByProgram(const ProgramInfo *proginfo)
GuideGrid * m_guide
Definition: guidegrid.cpp:242
const unsigned int m_firstRow
Definition: guidegrid.cpp:308
static bool IsTunable(uint chanid)
Definition: tv_play.cpp:8463
Dialog asking for user confirmation.
const QDateTime m_lastTime
Definition: guidegrid.cpp:322
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
void ExecuteUI(void) override
Definition: guidegrid.cpp:297
bool Delete(bool sendSig=true)
ChannelInfoList GetSelection(void) const
Definition: guidegrid.cpp:1273
static bool SelectionIsTunable(const ChannelInfoList &selection)
Definition: guidegrid.cpp:1059
void updateJumpToChannel(void)
Definition: guidegrid.cpp:2631
void cursorUp()
Definition: guidegrid.cpp:2425
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
#define ACTION_PAGERIGHT
Definition: tv_actions.h:12
QString toString(MarkTypes type)
const QDateTime m_currentStartTime
Definition: guidegrid.cpp:219
static ChannelInfoList LoadChannels(uint startIndex, uint count, uint &totalAvailable, bool ignoreHidden=true, OrderBy orderBy=kChanOrderByChanNum, GroupBy groupBy=kChanGroupByChanid, uint sourceID=0, uint channelGroupID=0, bool liveTVOnly=false, const QString &callsign="", const QString &channum="")
Load channels from database into a list of ChannelInfo objects.
Default local time.
Definition: mythdate.h:17
void ReturnPlayerLock(PlayerContext *&)
Definition: tv_play.cpp:13423
virtual void ShowUpcoming(void) const
Show the upcoming recordings for this title.
void SaveSetting(const QString &key, int newValue)
static Type MythEventMessage
Definition: mythevent.h:66
GuideUpdaterBase * m_updater
Definition: guidegrid.cpp:357
void SetRedraw(void)
Definition: mythuitype.cpp:295
void removeListener(QObject *listener)
Remove a listener to the observable.
const MythRect m_gg_programRect
Definition: guidegrid.cpp:217
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
QString GetFormatted(const ChannelFormat &format) const
QString m_entry
Definition: guidegrid.h:71
int getChannelCount(void)
Basic menu dialog, message and a list of options.
QDateTime m_lastTime
Definition: guidegrid.h:264
int m_timeCount
Definition: guidegrid.h:260
const QDateTime m_firstTime
Definition: guidegrid.cpp:224
#define ACTION_UP
Definition: mythuiactions.h:16
const int m_currentRow
Definition: guidegrid.cpp:221
const int m_channelCount
Definition: guidegrid.cpp:222
void aboutToShow() override
Definition: guidegrid.cpp:2702
QString GetTitle(void) const
Definition: programinfo.h:353
const QDateTime m_currentStartTime
Definition: guidegrid.cpp:313
void ResetRow(int row)
~GuideUpdateProgramRow() override=default
QTimer * m_updateTimer
Definition: guidegrid.h:276
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:136
#define ACTION_TOGGLERECORD
Definition: tv_actions.h:19
GuideHelper(GuideGrid *guide, GuideUpdaterBase *updater)
Definition: guidegrid.cpp:366
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
Definition: guidegrid.cpp:579
#define ACTION_TOGGLEPGORDER
Definition: tv_actions.h:13
void ToggleMute(PlayerContext *, const bool muteIndividualChannels=false)
Definition: tv_play.cpp:9027
PlayerContext * GetPlayerReadLock(int which, const char *file, int location)
Definition: tv_play.cpp:13360
#define ACTION_VOLUMEDOWN
Definition: tv_actions.h:112
vector< ChannelGroupItem > ChannelGroupList
Definition: channelgroup.h:32
QDateTime m_currentStartTime
Definition: guidegrid.h:248
MythScreenStack * GetStack(const QString &stackname)
ProgInfoGuideArray m_programInfos
Definition: guidegrid.cpp:325
int8_t m_spread
Definition: programinfo.h:812
ProgramList GetProgramList(uint chanid) const
Definition: guidegrid.cpp:1181
const bool m_verticalLayout
Definition: guidegrid.cpp:320
const unsigned long kUpdateMS
Definition: guidegrid.cpp:66
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void refreshVideo(void)
Definition: guidegrid.cpp:2686
AutoDeleteDeque< ProgramInfo * > ProgramList
Definition: programinfo.h:29
size_t size(void) const
ChannelInfo * GetChannelInfo(uint chan_idx, int sel=-1)
Definition: guidegrid.cpp:1148
void customEvent(QEvent *event) override
Definition: guidegrid.cpp:1861
MythScreenStack * GetMainStack()
virtual void ShowDetails(void) const
Show the Program Details screen.
uint GetAlternateChannelIndex(uint chan_idx, bool with_same_channum) const
Definition: guidegrid.cpp:1214
void addListener(QObject *listener)
Add a listener to the observable.
#define ACTION_RIGHT
Definition: mythuiactions.h:19
Gesture gesture(void) const
Get the gesture type.
Definition: mythgesture.h:107
void fillProgramRowInfosWith(int row, const QDateTime &start, ProgramList *proglist)
Definition: guidegrid.cpp:1628
static QMutex s_lock
Definition: guidegrid.cpp:410
const QDateTime m_currentEndTime
Definition: guidegrid.cpp:314
static const uint kJumpToChannelTimeout
Definition: guidegrid.h:77
JumpToChannel(JumpToChannelListener *parent, const QString &start_entry, int start_chan_idx, int cur_chan_idx, uint rows_disp)
Definition: guidegrid.cpp:69
bool isVerticalLayout(void)
static Type kEventType
Definition: guidegrid.cpp:358
QWaitCondition epgIsVisibleCond
Definition: guidegrid.cpp:58
static guint32 * tmp
Definition: goom_core.c:35
void GoTo(int start, int cur_row) override
Definition: guidegrid.cpp:2622
#define GridTimeEndsAfter
The base class on which all widgets and screens are based.
Definition: mythuitype.h:63
void SetProgPast(int ppast)
iterator begin(void)
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
virtual void SetJumpToChannel(JumpToChannel *ptr)=0
MythUIGuideGrid * m_guideGrid
Definition: guidegrid.h:288
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: guidegrid.cpp:670
void BuildFocusList(void)
bool Update(void)
Definition: guidegrid.cpp:165
static Type kEventType
Definition: mythdialogbox.h:50
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
#define ACTION_DAYLEFT
Definition: tv_actions.h:9
unsigned char r
Definition: ParseText.cpp:329
int GetStartChannelOffset(int row=-1) const
Definition: guidegrid.cpp:1171
void toggleChannelFavorite(int grpid=-1)
Definition: guidegrid.cpp:2318
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
Definition: guidegrid.cpp:604
#define ACTION_GUIDE
Definition: tv_actions.h:26
MythUIButtonList * m_channelList
Definition: guidegrid.h:287
static ProgramList * CopyProglist(ProgramList *proglist)
Definition: guidegrid.cpp:1203
QString m_icon
Definition: channelinfo.h:83
bool gestureEvent(MythGestureEvent *) override
Mouse click/movement handler, receives mouse gesture events from the QCoreApplication event loop.
const unsigned int m_numRows
Definition: guidegrid.cpp:309
virtual ~GuideUpdaterBase()=default
void channelUpdate()
Definition: guidegrid.cpp:2587
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:382
#define ACTION_SELECT
Definition: mythuiactions.h:15
void AddButton(const QString &title, QVariant data=0, bool newMenu=false, bool setCurrent=false)
Holds information on recordings and videos.
Definition: programinfo.h:66
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void SetScheduledEndTime(const QDateTime &dt)
Definition: programinfo.h:509
This class is used as a container for messages.
Definition: mythevent.h:16
def rating(profile, smoonURL, gate)
Definition: scan.py:25
void Close() override
Definition: guidegrid.cpp:2538
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
virtual void ShowPrevious(void) const
Show the previous recordings for this recording rule.
#define ACTION_DAYRIGHT
Definition: tv_actions.h:10
GuideUpdateProgramRow(GuideGrid *guide, const GuideStatus &gs, const QVector< ProgramList * > &proglists)
Definition: guidegrid.cpp:248
bool Create() override
bool empty(void) const
void volumeUpdate(bool)
Definition: guidegrid.cpp:2602
Default local time.
Definition: mythdate.h:19
MythUIButtonList * m_timeList
Definition: guidegrid.h:286
void aboutToHide() override
Definition: guidegrid.cpp:2694
A C++ ripoff of the stroke library for MythTV.
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
const QDateTime m_currentEndTime
Definition: guidegrid.cpp:219
QDateTime m_currentEndTime
Definition: guidegrid.h:249
static ChannelGroupList GetChannelGroups(bool includeEmpty=true)
static int GetNextChannelGroup(const ChannelGroupList &sorted, int grpid)
void toggleGuideListing()
Definition: guidegrid.cpp:2234
bool m_verticalLayout
Definition: guidegrid.h:261
void DrawUnusedRects(void)
Definition: tv_play.cpp:8599
virtual MythRect GetArea(void) const
If the object has a minimum area defined, return it, other wise return the default area.
Definition: mythuitype.cpp:863
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
GuideUpdaterBase(GuideGrid *guide)
Definition: guidegrid.cpp:230
GuideGrid(MythScreenStack *parentStack, uint chanid, const QString &channum, const QDateTime &startTime, TV *player=nullptr, bool embedVideo=false, bool allowFinder=true, int changrpid=-1)
Definition: guidegrid.cpp:491
QString GetEntry(void) const
Definition: guidegrid.h:60
QWidget * GetPaintWindow()
QDateTime m_originalStartTime
Definition: guidegrid.h:247
#define ACTION_TOGGLEFAV
Definition: tv_actions.h:20
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:84
int getTimeCount(void)
Default local time.
Definition: mythdate.h:16
void SetReturnEvent(QObject *retobject, const QString &resultid)
static ChannelInfoList GetChannels(uint sourceid, bool visible_only, const QString &group_by=QString(), uint channel_groupid=0)
Definition: channelutil.h:234
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:17
QLinkedList< GuideUIElement > m_result
Definition: guidegrid.cpp:328
static int GetChannelGroupId(const QString &changroupname)
void Reset(void) override
Reset the image back to the default defined in the theme.
const int m_timeCount
Definition: guidegrid.cpp:222
const int m_channelCount
Definition: guidegrid.cpp:318
QDateTime m_firstTime
Definition: guidegrid.h:263
virtual void SetTextFromMap(const InfoMap &infoMap)
Control TV playback.
Definition: tv_play.h:284
virtual void ExecuteUI(void)=0
ProgramList m_recList
Definition: guidegrid.h:245
MythUIText * m_jumpToText
Definition: guidegrid.h:291
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
MythRect m_Area
Definition: mythuitype.h:249
const int m_gg_channelCount
Definition: guidegrid.cpp:312
void toggleMute(const bool muteIndividualChannels=false)
Definition: guidegrid.cpp:2612
MythUIType * GetChildAt(const QPoint &p, bool recursive=true, bool focusable=true) const
Return the first MythUIType at the given coordinates.
Definition: mythuitype.cpp:223
#define GridTimeNormal
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:23
Internal representation of a recording rule, mirrors the record table.
Definition: recordingrule.h:32
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:389
MThreadPool m_threadPool
Definition: guidegrid.h:278
ProgInfoGuideArray m_programInfos
Definition: guidegrid.h:244
vector< uint > RemoteRequestFreeInputList(uint excluded_input)
void generateListings()
Definition: guidegrid.cpp:2252
A custom event that represents a mouse gesture.
Definition: mythgesture.h:39
void updateTimeout(void)
Definition: guidegrid.cpp:1350
const char * name
Definition: ParseText.cpp:328
static QString GetChannelGroupName(int grpid)
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
#define LOC
Definition: guidegrid.cpp:60
const bool m_verticalLayout
Definition: guidegrid.cpp:223
void fillTimeInfos(void)
Definition: guidegrid.cpp:1497
void cursorRight()
Definition: guidegrid.cpp:2384
void enter()
Definition: guidegrid.cpp:2523
uint m_rows_displayed
Definition: guidegrid.h:74
virtual void EditCustom(void)
Creates a dialog for creating a custom recording rule.
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
void moveToTime(const QDateTime &datetime)
Definition: guidegrid.cpp:2495
void updateChannelsNonUI(QVector< ChannelInfo * > &chinfos, QVector< bool > &unavailables)
Definition: guidegrid.cpp:2086
void customEvent(QEvent *) override
#define ACTION_FINDER
Definition: tv_actions.h:27
QString m_channum
Definition: channelinfo.h:76
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
QMutex m_jumpToChannelLock
Definition: guidegrid.h:283
void RunProgramFinder(TV *player, bool embedVideo, bool allowEPG)
Definition: progfind.cpp:35
#define GridTimeStartsBefore
QTimer * m_previewVideoRefreshTimer
Definition: guidegrid.h:269
TVState GetState(int player_idx) const
get tv state of active player context
Definition: tv_play.cpp:1436
void SetReturnEvent(QObject *retobject, const QString &resultid)
int m_channelCount
Definition: guidegrid.h:259
ProgramList * getProgramListFromProgram(int chanNum)
Definition: guidegrid.cpp:1537
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
int m_currentRow
Definition: guidegrid.h:254
int FindChannel(uint chanid, const QString &channum, bool exact=true) const override
Definition: guidegrid.cpp:1434
const QString kUnknownTitle
Definition: guidegrid.cpp:64
MythMainWindow * GetMythMainWindow(void)
const unsigned int m_numRows
Definition: guidegrid.cpp:215
static bool StartTV(ProgramInfo *tvrec, uint flags, const ChannelInfoList &selection=ChannelInfoList())
returns true if the recording completed when exiting.
Definition: tv_play.cpp:290
int m_previous_current_channel_index
Definition: guidegrid.h:73
#define MKKEY(IDX, SEL)
Definition: guidegrid.cpp:1272
const int m_gg_channelCount
Definition: guidegrid.cpp:218
virtual void ShowChannelSearch(void) const
Show the channel search.
vector< ChannelInfo > ChannelInfoList
Definition: channelinfo.h:120
void updateInfo(void)
Definition: guidegrid.cpp:2177
int GetNumSetting(const QString &key, int defaultval=0)
virtual bool ExecuteNonUI(void)=0
const QVector< int > m_channums
Definition: guidegrid.cpp:216
GuideUpdaterBase * m_updater
Definition: guidegrid.cpp:408
db_chan_list_list_t m_channelInfos
Definition: guidegrid.h:240
void SetJumpToChannel(JumpToChannel *ptr) override
Definition: guidegrid.cpp:2647
void UpdateChannelList(int groupID)
update the channel list with channels from the selected channel group
Definition: tv_play.cpp:1409
bool ExecuteNonUI(void) override
Definition: guidegrid.cpp:336
const uint m_currentStartChannel
Definition: guidegrid.cpp:315
bool keyPressEvent(QKeyEvent *) override
Key event handler.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void ShowMenu(void) override
Definition: guidegrid.cpp:1069
virtual void GoTo(int start, int cur_row)=0
void updateDateText(void)
Definition: guidegrid.cpp:2035
void ChannelGroupMenu(int mode=0)
Definition: guidegrid.cpp:2266
virtual void aboutToHide(void)
void HideTVWindow(void)
Definition: guidegrid.cpp:2661
QRect m_videoRect
Definition: guidegrid.h:272
void start(QRunnable *runnable, const QString &debugName, int priority=0)
int m_selectRecThreshold
Definition: guidegrid.h:237
QString m_title
Definition: recordingrule.h:79
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:439
QMap< uint, uint > m_channelInfoIdx
Definition: guidegrid.h:241
void fillChannelInfos(bool gotostartchannel=true)
Definition: guidegrid.cpp:1357
bool GetBoolSetting(const QString &key, bool defaultval=false)
#define ACTION_MUTEAUDIO
Definition: tv_actions.h:107
virtual void PopScreen(MythScreenType *screen=nullptr, bool allowFade=true, bool deleteScreen=true)
bool m_sortReverse
Definition: guidegrid.h:257
bool ProcessEntry(const QStringList &actions, const QKeyEvent *e)
Definition: guidegrid.cpp:117
MythUIText * m_longdateText
Definition: guidegrid.h:290
bool LoadFromProgram(ProgramList &destination, const QString &where, const QString &groupBy, const QString &orderBy, const MSqlBindings &bindings, const ProgramList &schedList)
bool Create(void) override
QVector< ChannelInfo * > m_chinfos
Definition: guidegrid.cpp:348
virtual void QuickRecord(void)
Create a kSingleRecord or bring up recording dialog.
virtual void EditScheduled(void)
Creates a dialog for editing the recording schedule.
const int m_currentCol
Definition: guidegrid.cpp:221
RecordingType GetRecordingRuleType(void) const
Definition: programinfo.h:443
GuideUpdateChannels(GuideGrid *guide, uint startChan)
Definition: guidegrid.cpp:334
static int GetNearestChannel(const ChannelInfoList &list, const QString &channum)
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
static void RunProgramGuide(uint startChanId, const QString &startChanNum, const QDateTime &startTime, TV *player=nullptr, bool embedVideo=false, bool allowFinder=true, int changrpid=-1)
Definition: guidegrid.cpp:418
TV * m_player
Definition: guidegrid.h:266
void SetReturnEvent(QObject *retobject, const QString &resultid)
const QDateTime m_firstTime
Definition: guidegrid.cpp:321
iterator end(void)
MythPoint topLeft(void) const
Definition: mythrect.cpp:244
const QVector< int > m_channums
Definition: guidegrid.cpp:310
void showProgFinder()
Definition: guidegrid.cpp:2517
static void Wait(GuideGrid *guide)
Definition: guidegrid.cpp:397
void SetFontState(const QString &state, const QString &name="")
#define MAX_DISPLAY_TIMES
uint GetRecordingRuleID(void) const
Definition: programinfo.h:441
bool LoadFromScheduler(AutoDeleteDeque< TYPE * > &destination, bool &hasConflicts, QString altTable="", int recordid=-1)
Definition: programinfo.h:876
bool gestureEvent(MythGestureEvent *event) override
Mouse click/movement handler, receives mouse gesture events from the QCoreApplication event loop.
vector< ProgramList * > m_programs
Definition: guidegrid.h:243
bool m_usingNullVideo
Definition: guidegrid.h:267
bool gestureEvent(MythGestureEvent *event) override
Mouse click/movement handler, receives mouse gesture events from the QCoreApplication event loop.
Definition: guidegrid.cpp:858
int8_t m_startCol
Definition: programinfo.h:813
bool DisplayState(const QString &name)
ProgramInfo * ProgInfoGuideArray[MAX_DISPLAY_CHANS][MAX_DISPLAY_TIMES]
Definition: guidegrid.h:36
void ExecuteUI(void) override
Definition: guidegrid.cpp:343
MythUIType * m_Parent
Definition: mythuitype.h:270
void ShowRecordingMenu(void)
Definition: guidegrid.cpp:1116
GuideGrid * m_guide
Definition: guidegrid.cpp:407
const QDateTime m_lastTime
Definition: guidegrid.cpp:224
QString GetMasterHostPrefix(const QString &storageGroup=QString(), const QString &path=QString())
virtual void deleteLater(void)
Definition: guidegrid.cpp:88
virtual int FindChannel(uint chanid, const QString &channum, bool exact=true) const =0
void fillProgramInfos(bool useExistingData=false)
Definition: guidegrid.cpp:1532
void SetItemCurrent(MythUIButtonListItem *item)
QString m_callsign
Definition: channelinfo.h:81
UpdateGuideEvent(GuideUpdaterBase *updater)
Definition: guidegrid.cpp:355
const unsigned int m_firstRow
Definition: guidegrid.cpp:215
#define ACTION_PAGELEFT
Definition: tv_actions.h:11
#define ACTION_CHANNELSEARCH
Definition: tv_actions.h:28
JumpToChannel * m_jumpToChannel
Definition: guidegrid.h:284
QMap< QString, QVariant > MSqlBindings
typedef for a map of string -> string bindings for generic queries.
Definition: mythdbcon.h:98
void updateProgramsUI(unsigned int firstRow, unsigned int numRows, int progPast, const QVector< ProgramList * > &proglists, const ProgInfoGuideArray &programInfos, const QLinkedList< GuideUIElement > &elements)
Definition: guidegrid.cpp:2044
void updateChannels(void)
Definition: guidegrid.cpp:2079
uint GetCurrentStartChannel(void) const
Definition: guidegrid.h:133
void ChangeChannel(const PlayerContext *, const ChannelInfoList &options)
Definition: tv_play.cpp:7850
static bool ToggleChannel(uint chanid, int changrpid, bool delete_chan)
void setStartChannel(int newStartChannel)
Definition: guidegrid.cpp:2507
const uint m_currentStartChannel
Definition: guidegrid.cpp:220
#define ACTION_LEFT
Definition: mythuiactions.h:18
void fillProgramRowInfos(int row, bool useExistingData)
Definition: guidegrid.cpp:1561
QString GetCategory(void) const
Definition: programinfo.h:361
#define MAX_DISPLAY_CHANS
void SetProgramInfo(int row, int col, const QRect &area, const QString &title, const QString &genre, int arrow, int recType, int recStat, bool selected)
ChannelGroupList m_changrplist
Definition: guidegrid.h:281
uint m_currentStartChannel
Definition: guidegrid.h:250
const QString & Message() const
Definition: mythevent.h:58
uint GetChannelCount(void) const
Definition: guidegrid.cpp:1166
QPoint GetRowAndColumn(QPoint position)
bool m_embedVideo
Definition: guidegrid.h:268
static const QString kATSCSeparators
Definition: channelutil.h:324
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:37
void ShowJumpToTime(void)
Definition: guidegrid.cpp:2710
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:132
MythUIText * m_dateText
Definition: guidegrid.h:289
void DisplayState(const QString &state, const QString &name)
void moveUpDown(MoveVector movement)
Definition: guidegrid.cpp:2471
vector< ChannelInfo > db_chan_list_t
Definition: guidegrid.h:32
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
void run(void) override
Definition: guidegrid.cpp:372
void EmbedTVWindow(void)
Definition: guidegrid.cpp:2666
QVector< ProgramList * > m_proglists
Definition: guidegrid.cpp:324
QVector< bool > m_unavailables
Definition: guidegrid.cpp:349
int m_currentCol
Definition: guidegrid.h:255
static bool has_action(const QString &action, const QStringList &actions)
Definition: guidegrid.cpp:106
static bool IsLoading(GuideGrid *guide)
Definition: guidegrid.cpp:392
GuideStatus(unsigned int firstRow, unsigned int numRows, const QVector< int > &channums, const MythRect &gg_programRect, int gg_channelCount, const QDateTime &currentStartTime, const QDateTime &currentEndTime, uint currentStartChannel, int currentRow, int currentCol, int channelCount, int timeCount, bool verticalLayout, const QDateTime &firstTime, const QDateTime &lastTime)
Definition: guidegrid.cpp:196
#define ACTION_DOWN
Definition: mythuiactions.h:17
void ChangeVolume(PlayerContext *, bool up, int newvolume=-1)
Definition: tv_play.cpp:8793
QString m_channelOrdering
Definition: guidegrid.h:274
const MythRect m_gg_programRect
Definition: guidegrid.cpp:311
void moveLeftRight(MoveVector movement)
Definition: guidegrid.cpp:2440
bool Create(void) override
Definition: guidegrid.cpp:534
void SetData(QVariant data)
int m_changrpid
Definition: guidegrid.h:280
uint m_chanid
Definition: channelinfo.h:75
MythUIText * m_changroupname
Definition: guidegrid.h:292
virtual void EditRecording(bool may_watch_now=false)
Creates a dialog for editing the recording status, blocking until user leaves dialog.
QTimer * m_timer
Definition: guidegrid.h:75
void updateChannelsUI(const QVector< ChannelInfo * > &chinfos, const QVector< bool > &unavailables)
Definition: guidegrid.cpp:2138
#define ACTION_VOLUMEUP
Definition: tv_actions.h:111
void LoadInBackground(QString message="")
bool Create(void) override
static QString GetStartingChannel(uint inputid)
Definition: cardutil.cpp:1684
void deleteRule()
Definition: guidegrid.cpp:2556