MythTV  master
mythnews.cpp
Go to the documentation of this file.
1 // POSIX headers
2 #include <unistd.h>
3 
4 // C headers
5 #include <cmath>
6 
7 // QT headers
8 #include <QCoreApplication>
9 #include <QDateTime>
10 #include <QDir>
11 #include <QTimer>
12 #include <QRegExp>
13 #include <QUrl>
14 
15 // MythTV headers
16 #include <mythuibuttonlist.h>
17 #include <mythmainwindow.h>
18 #include <mythdialogbox.h>
19 #include <mythcontext.h>
20 #include <mythuiimage.h>
21 #include <mythsystemlegacy.h>
22 #include <mythuitext.h>
23 #include <mythdate.h>
24 #include <mythdirs.h>
25 #include <mythdb.h>
26 #include <mythdownloadmanager.h>
27 
28 // MythNews headers
29 #include "mythnews.h"
30 #include "mythnewseditor.h"
31 #include "newsdbutil.h"
32 #include "mythnewsconfig.h"
33 
34 #define LOC QString("MythNews: ")
35 #define LOC_WARN QString("MythNews, Warning: ")
36 #define LOC_ERR QString("MythNews, Error: ")
37 
42 MythNews::MythNews(MythScreenStack *parent, const QString &name) :
43  MythScreenType(parent, name),
44  m_retrieveTimer(new QTimer(this)),
45  m_updateFreq(gCoreContext->GetNumSetting("NewsUpdateFrequency", 30)),
46  m_zoom(gCoreContext->GetSetting("WebBrowserZoomLevel", "1.0")),
47  m_browser(gCoreContext->GetSetting("WebBrowserCommand", ""))
48 {
49  // Setup cache directory
50 
51  QString fileprefix = GetConfDir();
52 
53  QDir dir(fileprefix);
54  if (!dir.exists())
55  dir.mkdir(fileprefix);
56  fileprefix += "/MythNews";
57  dir = QDir(fileprefix);
58  if (!dir.exists())
59  dir.mkdir(fileprefix);
60 
61  connect(m_retrieveTimer, SIGNAL(timeout()),
62  this, SLOT(slotRetrieveNews()));
63 
64  m_retrieveTimer->stop();
65  m_retrieveTimer->setSingleShot(false);
67 }
68 
70 {
71  QMutexLocker locker(&m_lock);
72 }
73 
74 bool MythNews::Create(void)
75 {
76  QMutexLocker locker(&m_lock);
77 
78  // Load the theme for this screen
79  bool foundtheme = LoadWindowFromXML("news-ui.xml", "news", this);
80  if (!foundtheme)
81  return false;
82 
83  bool err = false;
84  UIUtilE::Assign(this, m_sitesList, "siteslist", &err);
85  UIUtilE::Assign(this, m_articlesList, "articleslist", &err);
86  UIUtilE::Assign(this, m_titleText, "title", &err);
87  UIUtilE::Assign(this, m_descText, "description", &err);
88 
89  // these are all optional
90  UIUtilW::Assign(this, m_nositesText, "nosites", &err);
91  UIUtilW::Assign(this, m_updatedText, "updated", &err);
92  UIUtilW::Assign(this, m_thumbnailImage, "thumbnail", &err);
93  UIUtilW::Assign(this, m_enclosureImage, "enclosures", &err);
94  UIUtilW::Assign(this, m_downloadImage, "download", &err);
95  UIUtilW::Assign(this, m_podcastImage, "ispodcast", &err);
96 
97  if (err)
98  {
99  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'news'");
100  return false;
101  }
102 
103  if (m_nositesText)
104  {
105  m_nositesText->SetText(tr("You haven't configured MythNews to use any sites."));
106  m_nositesText->Hide();
107  }
108 
109  BuildFocusList();
110 
112 
113  loadSites();
115 
116  connect(m_sitesList, SIGNAL(itemSelected(MythUIButtonListItem*)),
117  this, SLOT( slotSiteSelected(MythUIButtonListItem*)));
118  connect(m_articlesList, SIGNAL(itemSelected( MythUIButtonListItem*)),
119  this, SLOT( updateInfoView(MythUIButtonListItem*)));
120  connect(m_articlesList, SIGNAL(itemClicked( MythUIButtonListItem*)),
121  this, SLOT( slotViewArticle(MythUIButtonListItem*)));
122 
123  return true;
124 }
125 
127 {
128  m_newsSites.clear();
129  m_sitesList->Reset();
130  m_articles.clear();
132 
133  m_titleText->Reset();
134  m_descText->Reset();
135 
136  if (m_updatedText)
137  m_updatedText->Reset();
138 
139  if (m_downloadImage)
141 
142  if (m_enclosureImage)
144 
145  if (m_podcastImage)
146  m_podcastImage->Hide();
147 
148  if (m_thumbnailImage)
150 }
151 
153 {
154  QMutexLocker locker(&m_lock);
155 
156  clearSites();
157 
158  MSqlQuery query(MSqlQuery::InitCon());
159  query.prepare(
160  "SELECT name, url, ico, updated, podcast "
161  "FROM newssites "
162  "ORDER BY name");
163 
164  if (!query.exec())
165  {
166  MythDB::DBError(LOC_ERR + "Could not load sites from DB", query);
167  return;
168  }
169 
170  while (query.next())
171  {
172  QString name = query.value(0).toString();
173  QString url = query.value(1).toString();
174  QString icon = query.value(2).toString();
175 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
176  QDateTime time = MythDate::fromTime_t(query.value(3).toUInt());
177 #else
178  QDateTime time = MythDate::fromSecsSinceEpoch(query.value(3).toLongLong());
179 #endif
180  bool podcast = query.value(4).toBool();
181  m_newsSites.push_back(new NewsSite(name, url, time, podcast));
182  }
183  std::sort(m_newsSites.begin(), m_newsSites.end(), NewsSite::sortByName);
184 
185  for (auto & site : m_newsSites)
186  {
187  auto *item = new MythUIButtonListItem(m_sitesList, site->name());
188  item->SetData(QVariant::fromValue(site));
189 
190  connect(site, SIGNAL(finished(NewsSite*)),
191  this, SLOT(slotNewsRetrieved(NewsSite*)));
192  }
193 
195 
196  if (m_nositesText)
197  {
198  if (m_newsSites.empty())
199  m_nositesText->Show();
200  else
201  m_nositesText->Hide();
202  }
203 }
204 
206 {
207  QMutexLocker locker(&m_lock);
208 
209  if (!selected)
210  return;
211 
212  NewsSite *site = nullptr;
213  NewsArticle article;
214 
216  {
217  article = m_articles[selected];
219  site = m_sitesList->GetItemCurrent()->GetData().value<NewsSite*>();
220  }
221  else
222  {
223  site = selected->GetData().value<NewsSite*>();
226  }
227 
229  {
230  if (!article.title().isEmpty())
231  {
232 
233  if (m_titleText)
234  m_titleText->SetText(article.title());
235 
236  if (m_descText)
237  {
238  QString artText = article.description();
239  // replace a few HTML characters
240  artText.replace("&#8232;", ""); // LSEP
241  artText.replace("&#8233;", ""); // PSEP
242  artText.replace("&#163;", u8"\u00A3"); // POUND
243  artText.replace("&#173;", ""); // ?
244  artText.replace("&#8211;", "-"); // EN-DASH
245  artText.replace("&#8220;", """"); // LEFT-DOUBLE-QUOTE
246  artText.replace("&#8221;", """"); // RIGHT-DOUBLE-QUOTE
247  artText.replace("&#8216;", "'"); // LEFT-SINGLE-QUOTE
248  artText.replace("&#8217;", "'"); // RIGHT-SINGLE-QUOTE
249  // Replace paragraph and break HTML with newlines
250  if( artText.contains(QRegExp("</(p|P)>")) )
251  {
252  artText.replace( QRegExp("<(p|P)>"), "");
253  artText.replace( QRegExp("</(p|P)>"), "\n\n");
254  }
255  else
256  {
257  artText.replace( QRegExp("<(p|P)>"), "\n\n");
258  artText.replace( QRegExp("</(p|P)>"), "");
259  }
260  artText.replace( QRegExp("<(br|BR|)/>"), "\n");
261  artText.replace( QRegExp("<(br|BR|)>"), "\n");
262  // These are done instead of simplifyWhitespace
263  // because that function also strips out newlines
264  // Replace tab characters with nothing
265  artText.replace( QRegExp("\t"), "");
266  // Replace double space with single
267  artText.replace( QRegExp(" "), "");
268  // Replace whitespace at beginning of lines with newline
269  artText.replace( QRegExp("\n "), "\n");
270  // Remove any remaining HTML tags
271  QRegExp removeHTML(QRegExp("</?.+>"));
272  removeHTML.setMinimal(true);
273  artText.remove((const QRegExp&) removeHTML);
274  artText = artText.trimmed();
275  m_descText->SetText(artText);
276  }
277 
278  if (!article.thumbnail().isEmpty())
279  {
280  if (m_thumbnailImage)
281  {
284 
285  if (!m_thumbnailImage->IsVisible())
287  }
288  }
289  else
290  {
291  if (site && !site->imageURL().isEmpty())
292  {
293  if (m_thumbnailImage)
294  {
297 
298  if (!m_thumbnailImage->IsVisible())
300  }
301  }
302  else
303  {
304  if (m_thumbnailImage)
306  }
307  }
308 
309  if (m_downloadImage)
310  {
311  if (!article.enclosure().isEmpty())
312  {
313  if (!m_downloadImage->IsVisible())
315  }
316  else
318  }
319 
320  if (m_enclosureImage)
321  {
322  if (!article.enclosure().isEmpty())
323  {
324  if (!m_enclosureImage->IsVisible())
326  }
327  else
329  }
330 
331  if (m_podcastImage)
332  m_podcastImage->Hide();
333  }
334  }
335  else
336  {
337  if (m_downloadImage)
339 
340  if (m_enclosureImage)
342 
343  if (m_podcastImage)
344  m_podcastImage->Hide();
345 
346  if (site)
347  {
348  if (m_titleText)
349  m_titleText->SetText(site->name());
350 
351  if (m_descText)
352  m_descText->SetText(site->description());
353 
356 
357  if (m_podcastImage && site->podcast())
358  m_podcastImage->Show();
359 
360  if (!site->imageURL().isEmpty())
361  {
362  if (m_thumbnailImage)
363  {
366 
367  if (!m_thumbnailImage->IsVisible())
369  }
370  }
371  }
372  }
373 
374  if (m_updatedText)
375  {
376 
377  if (site)
378  {
379  QString text(tr("Updated") + " - ");
380  QDateTime updated(site->lastUpdated());
381  if (updated.isValid()) {
382  text += MythDate::toString(site->lastUpdated(),
384  }
385  else
386  text += tr("Unknown");
387  m_updatedText->SetText(text);
388  }
389  }
390 }
391 
392 QString MythNews::formatSize(long long bytes, int prec)
393 {
394  long long sizeKB = bytes / 1024;
395 
396  if (sizeKB>1024*1024*1024) // Terabytes
397  {
398  double sizeGB = sizeKB/(1024*1024*1024.0);
399  return QString("%1 TB").arg(sizeGB, 0, 'f', (sizeGB>10)?0:prec);
400  }
401  if (sizeKB>1024*1024) // Gigabytes
402  {
403  double sizeGB = sizeKB/(1024*1024.0);
404  return QString("%1 GB").arg(sizeGB, 0, 'f', (sizeGB>10)?0:prec);
405  }
406  if (sizeKB>1024) // Megabytes
407  {
408  double sizeMB = sizeKB/1024.0;
409  return QString("%1 MB").arg(sizeMB, 0, 'f', (sizeMB>10)?0:prec);
410  }
411  // Kilobytes
412  return QString("%1 KB").arg(sizeKB);
413 }
414 
415 bool MythNews::keyPressEvent(QKeyEvent *event)
416 {
417  if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
418  return true;
419 
420  QStringList actions;
421  bool handled = GetMythMainWindow()->TranslateKeyPress("News", event, actions);
422 
423  for (int i = 0; i < actions.size() && !handled; i++)
424  {
425  QString action = actions[i];
426  handled = true;
427 
428  if (action == "RETRIEVENEWS")
430  else if (action == "CANCEL")
431  cancelRetrieve();
432  else if (action == "MENU")
433  ShowMenu();
434  else if (action == "EDIT")
435  ShowEditDialog(true);
436  else if (action == "DELETE")
437  deleteNewsSite();
438  else
439  handled = false;
440  }
441 
442  if (!handled && MythScreenType::keyPressEvent(event))
443  handled = true;
444 
445  return handled;
446 }
447 
449 {
450  QMutexLocker locker(&m_lock);
451 
452  if (m_newsSites.empty())
453  return;
454 
455  m_retrieveTimer->stop();
456 
457  for (auto & site : m_newsSites)
458  {
459  if (site->timeSinceLastUpdate() > m_updateFreq)
460  site->retrieve();
461  else
462  processAndShowNews(site);
463  }
464 
465  m_retrieveTimer->stop();
466  m_retrieveTimer->setSingleShot(false);
468 }
469 
471 {
472 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
473  unsigned int updated = site->lastUpdated().toTime_t();
474 #else
475  qint64 updated = site->lastUpdated().toSecsSinceEpoch();
476 #endif
477 
478  MSqlQuery query(MSqlQuery::InitCon());
479  query.prepare("UPDATE newssites SET updated = :UPDATED "
480  "WHERE name = :NAME ;");
481  query.bindValue(":UPDATED", updated);
482  query.bindValue(":NAME", site->name());
483  if (!query.exec() || !query.isActive())
484  MythDB::DBError("news update time", query);
485 
486  processAndShowNews(site);
487 }
488 
490 {
491  QMutexLocker locker(&m_lock);
492 
493  for (auto & site : m_newsSites)
494  {
495  site->stop();
496  processAndShowNews(site);
497  }
498 }
499 
501 {
502  QMutexLocker locker(&m_lock);
503 
504  if (!site)
505  return;
506 
507  site->process();
508 
510  if (!siteUIItem)
511  return;
512 
513  if (site != siteUIItem->GetData().value<NewsSite*>())
514  return;
515 
516  QString currItem = m_articlesList->GetValue();
517  int topPos = m_articlesList->GetTopItemPos();
518 
520  m_articles.clear();
521 
522  NewsArticle::List articles = site->GetArticleList();
523  for (auto & article : articles)
524  {
525  auto *item =
526  new MythUIButtonListItem(m_articlesList, article.title());
527  m_articles[item] = article;
528  }
529 
530  if (m_articlesList->MoveToNamedPosition(currItem))
532 }
533 
535 {
536  QMutexLocker locker(&m_lock);
537 
538  if (!item || item->GetData().isNull())
539  return;
540 
541  auto *site = item->GetData().value<NewsSite*>();
542  if (!site)
543  return;
544 
546  m_articles.clear();
547 
548  NewsArticle::List articles = site->GetArticleList();
549  for (auto & article : articles)
550  {
551  auto *blitem = new MythUIButtonListItem(m_articlesList, article.title());
552  m_articles[blitem] = article;
553  }
554 
555  updateInfoView(item);
556 }
557 
559 {
560  QMutexLocker locker(&m_lock);
561 
562  QMap<MythUIButtonListItem*,NewsArticle>::const_iterator it =
563  m_articles.find(articlesListItem);
564 
565  if (it == m_articles.end())
566  return;
567 
568  const NewsArticle article = *it;
569 
570  if (article.articleURL().isEmpty())
571  return;
572 
573  if (article.enclosure().isEmpty())
574  {
575  QString cmdUrl(article.articleURL());
576 
577  if (m_browser.isEmpty())
578  {
579  ShowOkPopup(tr("No browser command set! MythNews needs MythBrowser to be installed."));
580  return;
581  }
582 
583  // display the web page
584  if (m_browser.toLower() == "internal")
585  {
586  GetMythMainWindow()->HandleMedia("WebBrowser", cmdUrl);
587  return;
588  }
589 
590  QString cmd = m_browser;
591  cmd.replace("%ZOOM%", m_zoom);
592  cmd.replace("%URL%", cmdUrl);
593  cmd.replace('\'', "%27");
594  cmd.replace("&","\\&");
595  cmd.replace(";","\\;");
596 
597  GetMythMainWindow()->AllowInput(false);
599  GetMythMainWindow()->AllowInput(true);
600  return;
601  }
602 
603  playVideo(article);
604 }
605 
607 {
608  QMutexLocker locker(&m_lock);
609 
610  NewsSite *site = nullptr;
611 
612  if (edit)
613  {
615 
616  if (!siteListItem || siteListItem->GetData().isNull())
617  return;
618 
619  site = siteListItem->GetData().value<NewsSite*>();
620  }
621 
623 
624  auto *mythnewseditor = new MythNewsEditor(site, edit, mainStack,
625  "mythnewseditor");
626 
627  if (mythnewseditor->Create())
628  {
629  connect(mythnewseditor, SIGNAL(Exiting()), SLOT(loadSites()));
630  mainStack->AddScreen(mythnewseditor);
631  }
632  else
633  delete mythnewseditor;
634 }
635 
637 {
639 
640  auto *mythnewsconfig = new MythNewsConfig(mainStack, "mythnewsconfig");
641 
642  if (mythnewsconfig->Create())
643  {
644  connect(mythnewsconfig, SIGNAL(Exiting()), SLOT(loadSites()));
645  mainStack->AddScreen(mythnewsconfig);
646  }
647  else
648  delete mythnewsconfig;
649 }
650 
652 {
653  QMutexLocker locker(&m_lock);
654 
655  QString label = tr("Options");
656 
657  MythScreenStack *popupStack =
658  GetMythMainWindow()->GetStack("popup stack");
659 
660  m_menuPopup = new MythDialogBox(label, popupStack, "mythnewsmenupopup");
661 
662  if (m_menuPopup->Create())
663  {
664  popupStack->AddScreen(m_menuPopup);
665 
666  m_menuPopup->SetReturnEvent(this, "options");
667 
668  m_menuPopup->AddButton(tr("Manage Feeds"));
669  m_menuPopup->AddButton(tr("Add Feed"));
670  if (!m_newsSites.empty())
671  {
672  m_menuPopup->AddButton(tr("Edit Feed"));
673  m_menuPopup->AddButton(tr("Delete Feed"));
674  }
675  }
676  else
677  {
678  delete m_menuPopup;
679  m_menuPopup = nullptr;
680  }
681 }
682 
684 {
685  QMutexLocker locker(&m_lock);
686 
688 
689  if (siteUIItem && !siteUIItem->GetData().isNull())
690  {
691  auto *site = siteUIItem->GetData().value<NewsSite*>();
692  if (site)
693  {
694  removeFromDB(site->name());
695  loadSites();
696  }
697  }
698 }
699 
700 // does not need locking
701 void MythNews::playVideo(const NewsArticle &article)
702 {
703  GetMythMainWindow()->HandleMedia("Internal", article.enclosure(),
704  article.description(), article.title());
705 }
706 
707 // does not need locking
708 void MythNews::customEvent(QEvent *event)
709 {
710  if (event->type() == DialogCompletionEvent::kEventType)
711  {
712  auto dce = dynamic_cast<DialogCompletionEvent*>(event);
713  if (dce == nullptr)
714  return;
715 
716  QString resultid = dce->GetId();
717  int buttonnum = dce->GetResult();
718 
719  if (resultid == "options")
720  {
721  if (buttonnum == 0)
722  ShowFeedManager();
723  else if (buttonnum == 1)
724  ShowEditDialog(false);
725  else if (buttonnum == 2)
726  ShowEditDialog(true);
727  else if (buttonnum == 3)
728  deleteNewsSite();
729  }
730 
731  m_menuPopup = nullptr;
732  }
733 }
void processAndShowNews(NewsSite *site)
Definition: mythnews.cpp:500
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
bool podcast(void) const
Definition: newssite.cpp:108
QString name(void) const
Definition: newssite.cpp:96
NewsSite::List m_newsSites
Definition: mythnews.h:49
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
void Show(void)
void process(void)
Definition: newssite.cpp:220
~MythNews() override
Definition: mythnews.cpp:69
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
QString enclosure(void) const
Definition: newsarticle.h:28
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
void SetData(QVariant data)
void slotRetrieveNews(void)
Definition: mythnews.cpp:448
static QString formatSize(long long bytes, int prec)
Definition: mythnews.cpp:392
bool IsVisible(bool recurse=false) const
Definition: mythuitype.cpp:882
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
int GetTopItemPos(void) const
Basic menu dialog, message and a list of options.
void customEvent(QEvent *event) override
Definition: mythnews.cpp:708
MythUIText * m_nositesText
Definition: mythnews.h:63
int m_timerTimeout
Definition: mythnews.h:52
QString articleURL(void) const
Definition: newsarticle.h:25
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:135
void clearSites(void)
Definition: mythnews.cpp:126
void AllowInput(bool allow)
void slotNewsRetrieved(NewsSite *site)
Definition: mythnews.cpp:470
MythScreenStack * GetStack(const QString &stackname)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void ShowMenu(void) override
Definition: mythnews.cpp:651
MythScreenStack * GetMainStack()
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:23
QString description(void) const
Definition: newssite.cpp:114
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
void BuildFocusList(void)
static Type kEventType
Definition: mythdialogbox.h:56
static void playVideo(const NewsArticle &article)
Definition: mythnews.cpp:701
QString m_browser
Definition: mythnews.h:56
bool MoveToNamedPosition(const QString &position_name)
QString GetConfDir(void)
Definition: mythdirs.cpp:224
void Hide(void)
QVariant value(int i) const
Definition: mythdbcon.h:198
void slotSiteSelected(MythUIButtonListItem *item)
Definition: mythnews.cpp:534
void AddButton(const QString &title, QVariant data=0, bool newMenu=false, bool setCurrent=false)
Default local time.
Definition: mythdate.h:20
void deleteNewsSite(void)
Definition: mythnews.cpp:683
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
QMap< MythUIButtonListItem *, NewsArticle > m_articles
Definition: mythnews.h:61
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(uint seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
Definition: mythdate.cpp:88
MythNews(MythScreenStack *parent, const QString &name)
Creates a new MythNews Screen.
Definition: mythnews.cpp:42
void ShowFeedManager()
Definition: mythnews.cpp:636
void cancelRetrieve(void)
Definition: mythnews.cpp:489
void clear(void)
Definition: newssite.h:68
NewsArticle::List GetArticleList(void) const
Definition: newssite.cpp:134
MythUIImage * m_podcastImage
Definition: mythnews.h:71
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:83
bool isActive(void) const
Definition: mythdbcon.h:204
MythUIImage * m_downloadImage
Definition: mythnews.h:69
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
void slotViewArticle(MythUIButtonListItem *articlesListItem)
Definition: mythnews.cpp:558
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
QString m_zoom
Definition: mythnews.h:55
void updateInfoView(void)
uint myth_system(const QString &command, uint flags, uint timeout)
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
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)
virtual QString GetValue() const
MythUIImage * m_thumbnailImage
Definition: mythnews.h:68
QDateTime lastUpdated(void) const
Definition: newssite.cpp:140
static bool sortByName(NewsSite *a, NewsSite *b)
Definition: newssite.h:104
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
bool Create(void) override
Definition: mythnews.cpp:74
MythUIImage * m_enclosureImage
Definition: mythnews.h:70
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
avoid disabling UI drawing
Definition: mythsystem.h:35
QString imageURL(void) const
Definition: newssite.cpp:128
MythUIButtonList * m_articlesList
Definition: mythnews.h:60
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
void SetReturnEvent(QObject *retobject, const QString &resultid)
QTimer * m_retrieveTimer
Definition: mythnews.h:51
vector< NewsArticle > List
Definition: newsarticle.h:14
void ShowEditDialog(bool edit)
Definition: mythnews.cpp:606
QMutex m_lock
Definition: mythnews.h:48
bool removeFromDB(RSSSite *site)
Definition: netutils.cpp:686
void SetItemCurrent(MythUIButtonListItem *item)
bool SetFocusWidget(MythUIType *widget=nullptr)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
QString title(void) const
Definition: newsarticle.h:23
MythDialogBox * m_menuPopup
Definition: mythnews.h:57
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
bool HandleMedia(const QString &handler, const QString &mrl, const QString &plot="", const QString &title="", const QString &subtitle="", const QString &director="", int season=0, int episode=0, const QString &inetref="", int lenMins=120, const QString &year="1895", const QString &id="", bool useBookmarks=false)
MythUIButtonListItem * GetItemFirst() const
Screen in which all other widgets are contained and rendered.
MythUIText * m_titleText
Definition: mythnews.h:65
int GetCurrentPos() const
QString description(void) const
Definition: newsarticle.h:24
#define LOC_ERR
Definition: mythnews.cpp:36
QString thumbnail(void) const
Definition: newsarticle.h:26
MythUIText * m_updatedText
Definition: mythnews.h:64
unsigned int m_updateFreq
Definition: mythnews.h:53
MythUIText * m_descText
Definition: mythnews.h:66
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythnews.cpp:415
void loadSites(void)
Definition: mythnews.cpp:152
MythUIButtonListItem * GetItemCurrent() const
bool Create(void) override
MythUIButtonList * m_sitesList
Definition: mythnews.h:59