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