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  auto it = m_NewsSites.begin();
186  for (; it != m_NewsSites.end(); ++it)
187  {
188  auto *item = new MythUIButtonListItem(m_sitesList, (*it)->name());
189  item->SetData(qVariantFromValue(*it));
190 
191  connect(*it, SIGNAL(finished(NewsSite*)),
192  this, SLOT(slotNewsRetrieved(NewsSite*)));
193  }
194 
196 
197  if (m_nositesText)
198  {
199  if (m_NewsSites.empty())
200  m_nositesText->Show();
201  else
202  m_nositesText->Hide();
203  }
204 }
205 
207 {
208  QMutexLocker locker(&m_lock);
209 
210  if (!selected)
211  return;
212 
213  NewsSite *site = nullptr;
214  NewsArticle article;
215 
217  {
218  article = m_articles[selected];
220  site = m_sitesList->GetItemCurrent()->GetData().value<NewsSite*>();
221  }
222  else
223  {
224  site = selected->GetData().value<NewsSite*>();
227  }
228 
230  {
231  if (!article.title().isEmpty())
232  {
233 
234  if (m_titleText)
235  m_titleText->SetText(article.title());
236 
237  if (m_descText)
238  {
239  QString artText = article.description();
240  // replace a few HTML characters
241  artText.replace("&#8232;", ""); // LSEP
242  artText.replace("&#8233;", ""); // PSEP
243  artText.replace("&#163;", u8"\u00A3"); // POUND
244  artText.replace("&#173;", ""); // ?
245  artText.replace("&#8211;", "-"); // EN-DASH
246  artText.replace("&#8220;", """"); // LEFT-DOUBLE-QUOTE
247  artText.replace("&#8221;", """"); // RIGHT-DOUBLE-QUOTE
248  artText.replace("&#8216;", "'"); // LEFT-SINGLE-QUOTE
249  artText.replace("&#8217;", "'"); // RIGHT-SINGLE-QUOTE
250  // Replace paragraph and break HTML with newlines
251  if( artText.contains(QRegExp("</(p|P)>")) )
252  {
253  artText.replace( QRegExp("<(p|P)>"), "");
254  artText.replace( QRegExp("</(p|P)>"), "\n\n");
255  }
256  else
257  {
258  artText.replace( QRegExp("<(p|P)>"), "\n\n");
259  artText.replace( QRegExp("</(p|P)>"), "");
260  }
261  artText.replace( QRegExp("<(br|BR|)/>"), "\n");
262  artText.replace( QRegExp("<(br|BR|)>"), "\n");
263  // These are done instead of simplifyWhitespace
264  // because that function also strips out newlines
265  // Replace tab characters with nothing
266  artText.replace( QRegExp("\t"), "");
267  // Replace double space with single
268  artText.replace( QRegExp(" "), "");
269  // Replace whitespace at beginning of lines with newline
270  artText.replace( QRegExp("\n "), "\n");
271  // Remove any remaining HTML tags
272  QRegExp removeHTML(QRegExp("</?.+>"));
273  removeHTML.setMinimal(true);
274  artText.remove((const QRegExp&) removeHTML);
275  artText = artText.trimmed();
276  m_descText->SetText(artText);
277  }
278 
279  if (!article.thumbnail().isEmpty())
280  {
281  if (m_thumbnailImage)
282  {
285 
286  if (!m_thumbnailImage->IsVisible())
288  }
289  }
290  else
291  {
292  if (site && !site->imageURL().isEmpty())
293  {
294  if (m_thumbnailImage)
295  {
298 
299  if (!m_thumbnailImage->IsVisible())
301  }
302  }
303  else
304  {
305  if (m_thumbnailImage)
307  }
308  }
309 
310  if (m_downloadImage)
311  {
312  if (!article.enclosure().isEmpty())
313  {
314  if (!m_downloadImage->IsVisible())
316  }
317  else
319  }
320 
321  if (m_enclosureImage)
322  {
323  if (!article.enclosure().isEmpty())
324  {
325  if (!m_enclosureImage->IsVisible())
327  }
328  else
330  }
331 
332  if (m_podcastImage)
333  m_podcastImage->Hide();
334  }
335  }
336  else
337  {
338  if (m_downloadImage)
340 
341  if (m_enclosureImage)
343 
344  if (m_podcastImage)
345  m_podcastImage->Hide();
346 
347  if (site)
348  {
349  if (m_titleText)
350  m_titleText->SetText(site->name());
351 
352  if (m_descText)
353  m_descText->SetText(site->description());
354 
357 
358  if (m_podcastImage && site->podcast())
359  m_podcastImage->Show();
360 
361  if (!site->imageURL().isEmpty())
362  {
363  if (m_thumbnailImage)
364  {
367 
368  if (!m_thumbnailImage->IsVisible())
370  }
371  }
372  }
373  }
374 
375  if (m_updatedText)
376  {
377 
378  if (site)
379  {
380  QString text(tr("Updated") + " - ");
381  QDateTime updated(site->lastUpdated());
382  if (updated.isValid()) {
383  text += MythDate::toString(site->lastUpdated(),
385  }
386  else
387  text += tr("Unknown");
388  m_updatedText->SetText(text);
389  }
390  }
391 }
392 
393 QString MythNews::formatSize(long long bytes, int prec)
394 {
395  long long sizeKB = bytes / 1024;
396 
397  if (sizeKB>1024*1024*1024) // Terabytes
398  {
399  double sizeGB = sizeKB/(1024*1024*1024.0);
400  return QString("%1 TB").arg(sizeGB, 0, 'f', (sizeGB>10)?0:prec);
401  }
402  if (sizeKB>1024*1024) // Gigabytes
403  {
404  double sizeGB = sizeKB/(1024*1024.0);
405  return QString("%1 GB").arg(sizeGB, 0, 'f', (sizeGB>10)?0:prec);
406  }
407  if (sizeKB>1024) // Megabytes
408  {
409  double sizeMB = sizeKB/1024.0;
410  return QString("%1 MB").arg(sizeMB, 0, 'f', (sizeMB>10)?0:prec);
411  }
412  // Kilobytes
413  return QString("%1 KB").arg(sizeKB);
414 }
415 
416 bool MythNews::keyPressEvent(QKeyEvent *event)
417 {
418  if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
419  return true;
420 
421  QStringList actions;
422  bool handled = GetMythMainWindow()->TranslateKeyPress("News", event, actions);
423 
424  for (int i = 0; i < actions.size() && !handled; i++)
425  {
426  QString action = actions[i];
427  handled = true;
428 
429  if (action == "RETRIEVENEWS")
431  else if (action == "CANCEL")
432  cancelRetrieve();
433  else if (action == "MENU")
434  ShowMenu();
435  else if (action == "EDIT")
436  ShowEditDialog(true);
437  else if (action == "DELETE")
438  deleteNewsSite();
439  else
440  handled = false;
441  }
442 
443  if (!handled && MythScreenType::keyPressEvent(event))
444  handled = true;
445 
446  return handled;
447 }
448 
450 {
451  QMutexLocker locker(&m_lock);
452 
453  if (m_NewsSites.empty())
454  return;
455 
456  m_RetrieveTimer->stop();
457 
458  auto it = m_NewsSites.begin();
459  for (; it != m_NewsSites.end(); ++it)
460  {
461  if ((*it)->timeSinceLastUpdate() > m_UpdateFreq)
462  (*it)->retrieve();
463  else
464  processAndShowNews(*it);
465  }
466 
467  m_RetrieveTimer->stop();
468  m_RetrieveTimer->setSingleShot(false);
470 }
471 
473 {
474 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
475  unsigned int updated = site->lastUpdated().toTime_t();
476 #else
477  qint64 updated = site->lastUpdated().toSecsSinceEpoch();
478 #endif
479 
480  MSqlQuery query(MSqlQuery::InitCon());
481  query.prepare("UPDATE newssites SET updated = :UPDATED "
482  "WHERE name = :NAME ;");
483  query.bindValue(":UPDATED", updated);
484  query.bindValue(":NAME", site->name());
485  if (!query.exec() || !query.isActive())
486  MythDB::DBError("news update time", query);
487 
488  processAndShowNews(site);
489 }
490 
492 {
493  QMutexLocker locker(&m_lock);
494 
495  auto it = m_NewsSites.begin();
496  for (; it != m_NewsSites.end(); ++it)
497  {
498  (*it)->stop();
499  processAndShowNews(*it);
500  }
501 }
502 
504 {
505  QMutexLocker locker(&m_lock);
506 
507  if (!site)
508  return;
509 
510  site->process();
511 
513  if (!siteUIItem)
514  return;
515 
516  if (site != siteUIItem->GetData().value<NewsSite*>())
517  return;
518 
519  QString currItem = m_articlesList->GetValue();
520  int topPos = m_articlesList->GetTopItemPos();
521 
523  m_articles.clear();
524 
525  NewsArticle::List articles = site->GetArticleList();
526  auto it = articles.begin();
527  for (; it != articles.end(); ++it)
528  {
529  auto *item =
530  new MythUIButtonListItem(m_articlesList, (*it).title());
531  m_articles[item] = *it;
532  }
533 
534  if (m_articlesList->MoveToNamedPosition(currItem))
536 }
537 
539 {
540  QMutexLocker locker(&m_lock);
541 
542  if (!item || item->GetData().isNull())
543  return;
544 
545  auto *site = item->GetData().value<NewsSite*>();
546  if (!site)
547  return;
548 
550  m_articles.clear();
551 
552  NewsArticle::List articles = site->GetArticleList();
553  auto it = articles.begin();
554  for (; it != articles.end(); ++it)
555  {
556  auto *blitem = new MythUIButtonListItem(m_articlesList, (*it).title());
557  m_articles[blitem] = *it;
558  }
559 
560  updateInfoView(item);
561 }
562 
564 {
565  QMutexLocker locker(&m_lock);
566 
567  QMap<MythUIButtonListItem*,NewsArticle>::const_iterator it =
568  m_articles.find(articlesListItem);
569 
570  if (it == m_articles.end())
571  return;
572 
573  const NewsArticle article = *it;
574 
575  if (article.articleURL().isEmpty())
576  return;
577 
578  if (article.enclosure().isEmpty())
579  {
580  QString cmdUrl(article.articleURL());
581 
582  if (m_browser.isEmpty())
583  {
584  ShowOkPopup(tr("No browser command set! MythNews needs MythBrowser to be installed."));
585  return;
586  }
587 
588  // display the web page
589  if (m_browser.toLower() == "internal")
590  {
591  GetMythMainWindow()->HandleMedia("WebBrowser", cmdUrl);
592  return;
593  }
594 
595  QString cmd = m_browser;
596  cmd.replace("%ZOOM%", m_zoom);
597  cmd.replace("%URL%", cmdUrl);
598  cmd.replace('\'', "%27");
599  cmd.replace("&","\\&");
600  cmd.replace(";","\\;");
601 
602  GetMythMainWindow()->AllowInput(false);
604  GetMythMainWindow()->AllowInput(true);
605  return;
606  }
607 
608  playVideo(article);
609 }
610 
612 {
613  QMutexLocker locker(&m_lock);
614 
615  NewsSite *site = nullptr;
616 
617  if (edit)
618  {
620 
621  if (!siteListItem || siteListItem->GetData().isNull())
622  return;
623 
624  site = siteListItem->GetData().value<NewsSite*>();
625  }
626 
628 
629  auto *mythnewseditor = new MythNewsEditor(site, edit, mainStack,
630  "mythnewseditor");
631 
632  if (mythnewseditor->Create())
633  {
634  connect(mythnewseditor, SIGNAL(Exiting()), SLOT(loadSites()));
635  mainStack->AddScreen(mythnewseditor);
636  }
637  else
638  delete mythnewseditor;
639 }
640 
642 {
644 
645  auto *mythnewsconfig = new MythNewsConfig(mainStack, "mythnewsconfig");
646 
647  if (mythnewsconfig->Create())
648  {
649  connect(mythnewsconfig, SIGNAL(Exiting()), SLOT(loadSites()));
650  mainStack->AddScreen(mythnewsconfig);
651  }
652  else
653  delete mythnewsconfig;
654 }
655 
657 {
658  QMutexLocker locker(&m_lock);
659 
660  QString label = tr("Options");
661 
662  MythScreenStack *popupStack =
663  GetMythMainWindow()->GetStack("popup stack");
664 
665  m_menuPopup = new MythDialogBox(label, popupStack, "mythnewsmenupopup");
666 
667  if (m_menuPopup->Create())
668  {
669  popupStack->AddScreen(m_menuPopup);
670 
671  m_menuPopup->SetReturnEvent(this, "options");
672 
673  m_menuPopup->AddButton(tr("Manage Feeds"));
674  m_menuPopup->AddButton(tr("Add Feed"));
675  if (!m_NewsSites.empty())
676  {
677  m_menuPopup->AddButton(tr("Edit Feed"));
678  m_menuPopup->AddButton(tr("Delete Feed"));
679  }
680  }
681  else
682  {
683  delete m_menuPopup;
684  m_menuPopup = nullptr;
685  }
686 }
687 
689 {
690  QMutexLocker locker(&m_lock);
691 
693 
694  if (siteUIItem && !siteUIItem->GetData().isNull())
695  {
696  auto *site = siteUIItem->GetData().value<NewsSite*>();
697  if (site)
698  {
699  removeFromDB(site->name());
700  loadSites();
701  }
702  }
703 }
704 
705 // does not need locking
706 void MythNews::playVideo(const NewsArticle &article)
707 {
708  GetMythMainWindow()->HandleMedia("Internal", article.enclosure(),
709  article.description(), article.title());
710 }
711 
712 // does not need locking
713 void MythNews::customEvent(QEvent *event)
714 {
715  if (event->type() == DialogCompletionEvent::kEventType)
716  {
717  auto dce = dynamic_cast<DialogCompletionEvent*>(event);
718  if (dce == nullptr)
719  return;
720 
721  QString resultid = dce->GetId();
722  int buttonnum = dce->GetResult();
723 
724  if (resultid == "options")
725  {
726  if (buttonnum == 0)
727  ShowFeedManager();
728  else if (buttonnum == 1)
729  ShowEditDialog(false);
730  else if (buttonnum == 2)
731  ShowEditDialog(true);
732  else if (buttonnum == 3)
733  deleteNewsSite();
734  }
735 
736  m_menuPopup = nullptr;
737  }
738 }
void processAndShowNews(NewsSite *site)
Definition: mythnews.cpp:503
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:781
bool podcast(void) const
Definition: newssite.cpp:108
QString name(void) const
Definition: newssite.cpp:96
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:862
void customEvent(QEvent *) override
Definition: mythnews.cpp:713
void Show(void)
void process(void)
Definition: newssite.cpp:220
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:449
static QString formatSize(long long bytes, int prec)
Definition: mythnews.cpp:393
bool IsVisible(bool recurse=false) const
Definition: mythuitype.cpp:881
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 slotSiteSelected(MythUIButtonListItem *)
Definition: mythnews.cpp:538
MythUIText * m_nositesText
Definition: mythnews.h:63
QString articleURL(void) const
Definition: newsarticle.h:25
~MythNews()
Definition: mythnews.cpp:69
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:135
void clearSites(void)
Definition: mythnews.cpp:126
void AllowInput(bool allow)
MythScreenStack * GetStack(const QString &stackname)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void ShowMenu(void) override
Definition: mythnews.cpp:656
MythScreenStack * GetMainStack()
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:23
QString description(void) const
Definition: newssite.cpp:114
void slotNewsRetrieved(NewsSite *)
Definition: mythnews.cpp:472
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
static void playVideo(const NewsArticle &article)
Definition: mythnews.cpp:706
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 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:688
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void slotViewArticle(MythUIButtonListItem *)
Definition: mythnews.cpp:563
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:641
void cancelRetrieve(void)
Definition: mythnews.cpp:491
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
QTimer * m_RetrieveTimer
Definition: mythnews.h:51
int m_TimerTimeout
Definition: mythnews.h:52
NewsSite::List m_NewsSites
Definition: mythnews.h:49
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:534
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
bool keyPressEvent(QKeyEvent *) override
Key event handler.
Definition: mythnews.cpp:416
static bool sortByName(NewsSite *a, NewsSite *b)
Definition: newssite.h:104
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:806
bool Create(void) override
Definition: mythnews.cpp:74
MythUIImage * m_enclosureImage
Definition: mythnews.h:70
bool keyPressEvent(QKeyEvent *) override
Key event handler.
#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)
vector< NewsArticle > List
Definition: newsarticle.h:14
void ShowEditDialog(bool edit)
Definition: mythnews.cpp:611
QMutex m_lock
Definition: mythnews.h:48
bool removeFromDB(RSSSite *site)
Definition: netutils.cpp:682
void SetItemCurrent(MythUIButtonListItem *item)
bool SetFocusWidget(MythUIType *widget=nullptr)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:602
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
MythUIText * m_descText
Definition: mythnews.h:66
unsigned int m_UpdateFreq
Definition: mythnews.h:53
void loadSites(void)
Definition: mythnews.cpp:152
MythUIButtonListItem * GetItemCurrent() const
bool Create(void) override
MythUIButtonList * m_sitesList
Definition: mythnews.h:59