MythTV  master
channelrecpriority.cpp
Go to the documentation of this file.
1 
2 #include "channelrecpriority.h"
3 
4 #include <algorithm> // For std::sort()
5 #include <vector> // For std::vector
6 using namespace std;
7 
8 #include "tv.h"
9 
10 #include "mythcorecontext.h"
11 #include "mythdb.h"
12 #include "mythlogging.h"
13 #include "scheduledrecording.h"
14 #include "proglist.h"
15 #include "channelinfo.h"
16 
17 #include "mythuihelper.h"
18 #include "mythuitext.h"
19 #include "mythuiimage.h"
20 #include "mythuibuttonlist.h"
21 #include "mythdialogbox.h"
22 #include "mythmainwindow.h"
23 
24 typedef struct RecPriorityInfo
25 {
27  int cnt;
29 
31 {
32  public:
34  {
35  if (a.chan->m_channum.toInt() == b.chan->m_channum.toInt())
36  return(a.chan->m_sourceid > b.chan->m_sourceid);
37  return(a.chan->m_channum.toInt() > b.chan->m_channum.toInt());
38  }
39 };
40 
42 {
43  public:
45  {
46  if (a.chan->m_recpriority == b.chan->m_recpriority)
47  return (a.chan->m_channum.toInt() > b.chan->m_channum.toInt());
48  return (a.chan->m_recpriority < b.chan->m_recpriority);
49  }
50 };
51 
53  : MythScreenType(parent, "ChannelRecPriority")
54 {
55  m_sortType = (SortType)gCoreContext->GetNumSetting("ChannelRecPrioritySorting",
56  (int)byChannel);
57 
59 }
60 
62 {
64  gCoreContext->SaveSetting("ChannelRecPrioritySorting",
65  (int)m_sortType);
67 }
68 
70 {
71  if (!LoadWindowFromXML("schedule-ui.xml", "channelrecpriority", this))
72  return false;
73 
74  m_channelList = dynamic_cast<MythUIButtonList *> (GetChild("channels"));
75 
76  m_chanstringText = dynamic_cast<MythUIText *> (GetChild("chanstring")); // Deprecated, use mapped text
77  m_priorityText = dynamic_cast<MythUIText *> (GetChild("priority"));
78 
79  m_iconImage = dynamic_cast<MythUIImage *> (GetChild("icon"));
80 
81  if (!m_channelList)
82  {
83  LOG(VB_GENERAL, LOG_ERR, "Theme is missing critical theme elements.");
84  return false;
85  }
86 
87  connect(m_channelList, SIGNAL(itemSelected(MythUIButtonListItem*)),
89 
90  FillList();
91 
93 
94  return true;
95 }
96 
97 bool ChannelRecPriority::keyPressEvent(QKeyEvent *event)
98 {
99  if (GetFocusWidget()->keyPressEvent(event))
100  return true;
101 
102  QStringList actions;
103  bool handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend", event, actions);
104 
105  for (int i = 0; i < actions.size() && !handled; i++)
106  {
107  QString action = actions[i];
108  handled = true;
109 
110  if (action == "UPCOMING")
111  upcoming();
112  else if (action == "RANKINC")
114  else if (action == "RANKDEC")
115  changeRecPriority(-1);
116  else if (action == "1")
117  {
118  if (m_sortType != byChannel)
119  {
121  SortList();
122  }
123  }
124  else if (action == "2")
125  {
126  if (m_sortType != byRecPriority)
127  {
129  SortList();
130  }
131  }
132  else if (action == "PREVVIEW" || action == "NEXTVIEW")
133  {
134  if (m_sortType == byChannel)
136  else
138  SortList();
139  }
140  else
141  handled = false;
142  }
143 
144  if (!handled && MythScreenType::keyPressEvent(event))
145  handled = true;
146 
147  return handled;
148 }
149 
151 {
153 
154  if (!item)
155  return;
156 
157  QString label = tr("Channel Options");
158 
159  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
160 
161  MythDialogBox *menuPopup = new MythDialogBox(label, popupStack,
162  "chanrecmenupopup");
163 
164  if (!menuPopup->Create())
165  {
166  delete menuPopup;
167  menuPopup = nullptr;
168  return;
169  }
170 
171  menuPopup->SetReturnEvent(this, "options");
172 
173  menuPopup->AddButton(tr("Program List"));
174  //menuPopup->AddButton(tr("Reset All Priorities"));
175 
176  popupStack->AddScreen(menuPopup);
177 }
178 
180 {
182 
183  if (!item)
184  return;
185 
186  ChannelInfo *chanInfo = item->GetData().value<ChannelInfo *>();
187 
188  // inc/dec recording priority
189  int tempRecPriority = chanInfo->m_recpriority + howMuch;
190  if (tempRecPriority > -100 && tempRecPriority < 100)
191  {
192  chanInfo->m_recpriority = tempRecPriority;
193 
194  // order may change if sorting by recoring priority, so resort
195  if (m_sortType == byRecPriority)
196  SortList();
197  else
198  {
199  item->SetText(QString::number(chanInfo->m_recpriority), "priority");
200  updateInfo(item);
201  }
202  }
203 }
204 
206  const QString &newrecpriority)
207 {
208  MSqlQuery query(MSqlQuery::InitCon());
209  query.prepare("UPDATE channel SET recpriority = :RECPRI "
210  "WHERE chanid = :CHANID ;");
211  query.bindValue(":RECPRI", newrecpriority);
212  query.bindValue(":CHANID", chanid);
213 
214  if (!query.exec() || !query.isActive())
215  MythDB::DBError("Save recpriority update", query);
216 }
217 
219 {
220  QMap<QString, ChannelInfo>::Iterator it;
221 
222  for (it = m_channelData.begin(); it != m_channelData.end(); ++it)
223  {
224  ChannelInfo *chanInfo = &(*it);
225  QString key = QString::number(chanInfo->m_chanid);
226 
227  // if this channel's recording priority changed from when we entered
228  // save new value out to db
229  if (QString::number(chanInfo->m_recpriority) != m_origRecPriorityData[key])
230  applyChannelRecPriorityChange(QString::number(chanInfo->m_chanid),
231  QString::number(chanInfo->m_recpriority));
232  }
233  ScheduledRecording::ReschedulePlace("SaveChannelPriority");
234 }
235 
237 {
238  QMap<int, QString> srcMap;
239 
240  m_channelData.clear();
241  m_sortedChannel.clear();
242 
243  MSqlQuery result(MSqlQuery::InitCon());
244  result.prepare("SELECT sourceid, name FROM videosource;");
245 
246  if (result.exec())
247  {
248  while (result.next())
249  {
250  srcMap[result.value(0).toInt()] = result.value(1).toString();
251  }
252  }
253  result.prepare("SELECT chanid, channum, sourceid, callsign, "
254  "icon, recpriority, name FROM channel WHERE visible=1;");
255 
256  if (result.exec())
257  {
258  int cnt = 999;
259  while (result.next())
260  {
261  ChannelInfo *chaninfo = new ChannelInfo;
262  chaninfo->m_chanid = result.value(0).toInt();
263  chaninfo->m_channum = result.value(1).toString();
264  chaninfo->m_sourceid = result.value(2).toInt();
265  chaninfo->m_callsign = result.value(3).toString();
266  QString iconurl = result.value(4).toString();
267  if (!iconurl.isEmpty())
268  iconurl = gCoreContext->GetMasterHostPrefix( "ChannelIcons", iconurl);
269  chaninfo->m_icon = iconurl;
270  chaninfo->m_recpriority = result.value(5).toInt();
271  chaninfo->m_name = result.value(6).toString();
272 
273  chaninfo->SetSourceName(srcMap[chaninfo->m_sourceid]);
274 
275  m_channelData[QString::number(cnt)] = *chaninfo;
276 
277  // save recording priority value in map so we don't have to save
278  // all channel's recording priority values when we exit
279  m_origRecPriorityData[QString::number(chaninfo->m_chanid)] =
280  chaninfo->m_recpriority;
281 
282  cnt--;
283  }
284  }
285  else if (!result.isActive())
286  MythDB::DBError("Get channel recording priorities query", result);
287 
288  SortList();
289 }
290 
292 {
293  m_channelList->Reset();
294 
295  QMap<QString, ChannelInfo*>::Iterator it;
296  for (it = m_sortedChannel.begin(); it != m_sortedChannel.end(); ++it)
297  {
298  ChannelInfo *chanInfo = *it;
299 
300  MythUIButtonListItem *item =
302  qVariantFromValue(chanInfo));
303 
304  QString fontState = "default";
305 
307  fontState);
308 
309  InfoMap infomap;
310  chanInfo->ToMap(infomap);
311  item->SetTextFromMap(infomap, fontState);
312 
313  item->DisplayState("normal", "status");
314 
315  if (!chanInfo->m_icon.isEmpty())
316  {
317  QString iconUrl = gCoreContext->GetMasterHostPrefix("ChannelIcons",
318  chanInfo->m_icon);
319  item->SetImage(iconUrl, "icon");
320  item->SetImage(iconUrl);
321  }
322 
323  item->SetText(QString::number(chanInfo->m_recpriority), "priority", fontState);
324 
325  if (m_currentItem == chanInfo)
327  }
328 
329  // this textarea name is depreciated use 'nochannels_warning' instead
330  MythUIText *noChannelsText = dynamic_cast<MythUIText*>(GetChild("norecordings_info"));
331 
332  if (!noChannelsText)
333  noChannelsText = dynamic_cast<MythUIText*>(GetChild("nochannels_warning"));
334 
335  if (noChannelsText)
336  noChannelsText->SetVisible(m_channelData.isEmpty());
337 }
338 
339 
341 {
343 
344  if (item)
345  {
346  ChannelInfo *channelItem = item->GetData().value<ChannelInfo *>();
347  m_currentItem = channelItem;
348  }
349 
350  int i, j;
351  vector<RecPriorityInfo> sortingList;
352  QMap<QString, ChannelInfo>::iterator pit;
353  vector<RecPriorityInfo>::iterator sit;
354 
355  // copy m_channelData into sortingList
356  for (i = 0, pit = m_channelData.begin(); pit != m_channelData.end();
357  ++pit, ++i)
358  {
359  ChannelInfo *chanInfo = &(*pit);
360  RecPriorityInfo tmp = {chanInfo, i};
361  sortingList.push_back(tmp);
362  }
363 
364  switch(m_sortType)
365  {
366  case byRecPriority:
367  sort(sortingList.begin(), sortingList.end(),
369  break;
370  case byChannel:
371  default:
372  sort(sortingList.begin(), sortingList.end(),
373  channelSort());
374  break;
375  }
376 
377  m_sortedChannel.clear();
378 
379  // rebuild m_channelData in sortingList order from m_sortedChannel
380  for (i = 0, sit = sortingList.begin(); sit != sortingList.end(); i++, ++sit)
381  {
382  RecPriorityInfo *recPriorityInfo = &(*sit);
383 
384  // find recPriorityInfo[i] in m_sortedChannel
385  for (j = 0, pit = m_channelData.begin(); j !=recPriorityInfo->cnt; j++, ++pit);
386 
387  m_sortedChannel[QString::number(999-i)] = &(*pit);
388  }
389 
390  updateList();
391 }
392 
394 {
395  if (!item)
396  return;
397 
398  ChannelInfo *channelItem = item->GetData().value<ChannelInfo *>();
399  if (!m_channelData.isEmpty() && channelItem)
400  {
401  QString rectype;
402  if (m_iconImage)
403  {
404  QString iconUrl = gCoreContext->GetMasterHostPrefix("ChannelIcons", channelItem->m_icon);
405  m_iconImage->SetFilename(iconUrl);
406  m_iconImage->Load();
407  }
408 
409  InfoMap chanmap;
410  channelItem->ToMap(chanmap);
411  SetTextFromMap(chanmap);
412 
413  if (m_chanstringText)
415  }
416 
417  MythUIText *norecordingText = dynamic_cast<MythUIText*>
418  (GetChild("norecordings_info"));
419 
420  if (norecordingText)
421  norecordingText->SetVisible(m_channelData.isEmpty());
422 }
423 
425 {
427 
428  if (!item)
429  return;
430 
431  ChannelInfo *chanInfo = item->GetData().value<ChannelInfo *>();
432 
433  if (!chanInfo || chanInfo->m_chanid < 1)
434  return;
435 
436  QString chanID = QString("%1").arg(chanInfo->m_chanid);
438  ProgLister *pl = new ProgLister(mainStack, plChannel, chanID, "");
439  if (pl->Create())
440  mainStack->AddScreen(pl);
441  else
442  delete pl;
443 }
444 
445 
447 {
448  if (event->type() == DialogCompletionEvent::kEventType)
449  {
451 
452  QString resultid = dce->GetId();
453  int buttonnum = dce->GetResult();
454 
455  if (resultid == "options")
456  {
457  switch (buttonnum)
458  {
459  case 0:
460  upcoming();
461  break;
462  }
463  }
464  }
465 }
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
void ToMap(InfoMap &infoMap)
QString m_name
Definition: channelinfo.h:82
MythUIImage * m_iconImage
int m_recpriority
Definition: channelinfo.h:88
void SetSourceName(const QString &lname)
Definition: channelinfo.h:44
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
ChannelRecPriority(MythScreenStack *parent)
All purpose text widget, displays a text string.
Definition: mythuitext.h:28
void SaveSetting(const QString &key, int newValue)
void removeListener(QObject *listener)
Remove a listener to the observable.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
QString GetFormatted(const ChannelFormat &format) const
bool Create(void) override
Definition: proglist.cpp:98
Basic menu dialog, message and a list of options.
MythUIText * m_priorityText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:136
void ShowMenu(void) override
void changeRecPriority(int howMuch)
ChannelInfo * m_currentItem
MythScreenStack * GetStack(const QString &stackname)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythUIButtonList * m_channelList
MythScreenStack * GetMainStack()
void addListener(QObject *listener)
Add a listener to the observable.
QMap< QString, ChannelInfo > m_channelData
static guint32 * tmp
Definition: goom_core.c:35
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
void BuildFocusList(void)
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.
QString m_icon
Definition: channelinfo.h:83
unsigned char b
Definition: ParseText.cpp:329
bool Create(void) override
QVariant value(int i) const
Definition: mythdbcon.h:198
void AddButton(const QString &title, QVariant data=0, bool newMenu=false, bool setCurrent=false)
virtual void SetVisible(bool visible)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void updateInfo(MythUIButtonListItem *)
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
QMap< QString, ChannelInfo * > m_sortedChannel
uint m_sourceid
Definition: channelinfo.h:79
bool isActive(void) const
Definition: mythdbcon.h:204
virtual void SetTextFromMap(const InfoMap &infoMap)
static void ReschedulePlace(const QString &why)
void SetText(const QString &text, const QString &name="", const QString &state="")
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
QString m_channum
Definition: channelinfo.h:76
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
MythUIType * GetFocusWidget(void) const
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
MythMainWindow * GetMythMainWindow(void)
struct RecPriorityInfo RecPriorityInfo
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:807
bool keyPressEvent(QKeyEvent *) override
Key event handler.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
MythUIText * m_chanstringText
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
void SetReturnEvent(QObject *retobject, const QString &resultid)
QString GetMasterHostPrefix(const QString &storageGroup=QString(), const QString &path=QString())
void SetItemCurrent(MythUIButtonListItem *item)
QString m_callsign
Definition: channelinfo.h:81
void applyChannelRecPriorityChange(const QString &, const QString &)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
Screen in which all other widgets are contained and rendered.
bool operator()(const RecPriorityInfo &a, const RecPriorityInfo &b)
void customEvent(QEvent *event) override
bool operator()(const RecPriorityInfo &a, const RecPriorityInfo &b)
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:37
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:132
QMap< QString, QString > m_origRecPriorityData
void DisplayState(const QString &state, const QString &name)
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
bool keyPressEvent(QKeyEvent *) override
Key event handler.
uint m_chanid
Definition: channelinfo.h:75
MythUIButtonListItem * GetItemCurrent() const
bool Create(void) override