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