Go to the documentation of this file.
8 #include <QCoreApplication>
11 #include <QRegularExpression>
34 #define LOC QString("MythNews: ")
35 #define LOC_WARN QString("MythNews, Warning: ")
36 #define LOC_ERR QString("MythNews, Error: ")
44 m_retrieveTimer(new QTimer(this)),
45 m_updateFreq(
gCoreContext->GetDurSetting<std::chrono::minutes>(
"NewsUpdateFrequency", 30min)),
46 m_zoom(
gCoreContext->GetSetting(
"WebBrowserZoomLevel",
"1.0")),
47 m_browser(
gCoreContext->GetSetting(
"WebBrowserCommand",
""))
55 dir.mkdir(fileprefix);
56 fileprefix +=
"/MythNews";
57 dir.setPath(fileprefix);;
59 dir.mkdir(fileprefix);
71 QMutexLocker locker(&
m_lock);
76 QMutexLocker locker(&
m_lock);
99 LOG(VB_GENERAL, LOG_ERR,
"Cannot load screen 'news'");
154 QMutexLocker locker(&
m_lock);
160 "SELECT name, url, ico, updated, podcast "
172 QString name = query.
value(0).toString();
173 QString url = query.
value(1).toString();
176 bool podcast = query.
value(4).toBool();
184 item->SetData(QVariant::fromValue(site));
203 QMutexLocker locker(&
m_lock);
226 if (!article.
title().isEmpty())
254 if (site && !site->
imageURL().isEmpty())
346 QString text(tr(
"Updated") +
" - ");
348 if (updated.isValid()) {
354 text += tr(
"Unknown");
369 for (
int i = 0; i < actions.size() && !handled; i++)
371 const QString&
action = actions[i];
374 if (
action ==
"RETRIEVENEWS")
376 else if (
action ==
"CANCEL")
378 else if (
action ==
"MENU")
380 else if (
action ==
"EDIT")
382 else if (
action ==
"DELETE")
396 QMutexLocker locker(&
m_lock);
418 qint64 updated = site->
lastUpdated().toSecsSinceEpoch();
421 query.
prepare(
"UPDATE newssites SET updated = :UPDATED "
422 "WHERE name = :NAME ;");
433 QMutexLocker locker(&
m_lock);
444 QMutexLocker locker(&
m_lock);
465 for (
auto & article : articles)
478 QMutexLocker locker(&
m_lock);
480 if (!item || item->
GetData().isNull())
491 for (
auto & article : articles)
502 QMutexLocker locker(&
m_lock);
504 QMap<MythUIButtonListItem*,NewsArticle>::const_iterator it =
521 ShowOkPopup(tr(
"No browser command set! MythNews needs MythBrowser to be installed."));
533 cmd.replace(
"%ZOOM%",
m_zoom);
534 cmd.replace(
"%URL%", cmdUrl);
535 cmd.replace(
'\'',
"%27");
536 cmd.replace(
"&",
"\\&");
537 cmd.replace(
";",
"\\;");
550 QMutexLocker locker(&
m_lock);
558 if (!siteListItem || siteListItem->
GetData().isNull())
569 if (mythnewseditor->Create())
576 delete mythnewseditor;
584 auto *mythnewsconfig =
new MythNewsConfig(mainStack,
"mythnewsconfig");
586 if (mythnewsconfig->Create())
593 delete mythnewsconfig;
599 QMutexLocker locker(&
m_lock);
601 QString label = tr(
"Options");
631 QMutexLocker locker(&
m_lock);
635 if (siteUIItem && !siteUIItem->
GetData().isNull())
662 QString resultid = dce->
GetId();
663 int buttonnum = dce->GetResult();
665 if (resultid ==
"options")
669 else if (buttonnum == 1)
671 else if (buttonnum == 2)
673 else if (buttonnum == 3)
683 QString result = text;
686 result.replace(
"
",
"");
687 result.replace(
"
",
"");
688 result.replace(
"£", u8
"\u00A3");
689 result.replace(
"­",
"");
690 result.replace(
"–",
"-");
691 result.replace(
"“",
"""");
692 result.replace(
"”",
"""");
693 result.replace(
"‘",
"'");
694 result.replace(
"’",
"'");
695 result.replace(
"'",
"'");
698 static const QRegularExpression kHtmlParaStartRE
699 {
"<p>", QRegularExpression::CaseInsensitiveOption };
700 static const QRegularExpression kHtmlParaEndRE
701 {
"</p>", QRegularExpression::CaseInsensitiveOption };
702 static const QRegularExpression kHtmlBreak1RE
703 {
"<(br|)>", QRegularExpression::CaseInsensitiveOption };
704 static const QRegularExpression kHtmlBreak2RE
705 {
"<(br|)/>", QRegularExpression::CaseInsensitiveOption };
706 if( result.contains(kHtmlParaEndRE) )
708 result.replace( kHtmlParaStartRE,
"");
709 result.replace( kHtmlParaEndRE,
"\n\n");
713 result.replace( kHtmlParaStartRE,
"\n\n");
714 result.replace( kHtmlParaEndRE,
"");
716 result.replace( kHtmlBreak2RE,
"\n");
717 result.replace( kHtmlBreak1RE,
"\n");
721 static const QRegularExpression kTabRE {
"\t" };
722 result.replace( kTabRE,
"");
724 static const QRegularExpression kTwoSpaceRE {
" " };
725 result.replace( kTwoSpaceRE,
"");
727 static const QRegularExpression kStartingSpaceRE {
"\n " };
728 result.replace( kStartingSpaceRE,
"\n");
730 static const QRegularExpression kRemoveHtmlRE(QRegularExpression(
"</?.+>"));
731 result.remove(kRemoveHtmlRE);
732 result = result.trimmed();
void ShowMenu(void) override
bool isActive(void) const
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
MythScreenStack * GetMainStack()
QString imageURL(void) const
void SetReturnEvent(QObject *retobject, const QString &resultid)
MythUIText * m_updatedText
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
NewsSite::List m_newsSites
QString articleURL(void) const
static QString cleanText(const QString &text)
MythUIText * m_nositesText
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
void slotNewsRetrieved(NewsSite *site)
QString title(void) const
MythDialogBox * m_menuPopup
void processAndShowNews(NewsSite *site)
QString thumbnail(void) const
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
void slotRetrieveNews(void)
void customEvent(QEvent *event) override
void finished(NewsSite *item)
QVariant value(int i) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Screen in which all other widgets are contained and rendered.
QString description(void) const
QMap< MythUIButtonListItem *, NewsArticle > m_articles
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
void slotViewArticle(MythUIButtonListItem *articlesListItem)
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="", std::chrono::minutes LenMins=2h, const QString &Year="1895", const QString &Id="", bool UseBookmarks=false)
static bool sortByName(NewsSite *a, NewsSite *b)
MythNews(MythScreenStack *parent, const QString &name)
Creates a new MythNews Screen.
MythUIType * GetFocusWidget(void) const
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(int64_t seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
MythUIImage * m_downloadImage
void ShowFeedManager() const
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
bool SetFocusWidget(MythUIType *widget=nullptr)
void AddButton(const QString &title)
Basic menu dialog, message and a list of options.
bool removeFromDB(RSSSite *site)
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
static void playVideo(const NewsArticle &article)
bool Create(void) override
static void DBError(const QString &where, const MSqlQuery &query)
void BuildFocusList(void)
QDateTime lastUpdated(void) const
void deleteNewsSite(void)
NewsArticle::List GetArticleList(void) const
void updateInfoView(void)
void cancelRetrieve(void)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythUIImage * m_podcastImage
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
MythUIButtonList * m_articlesList
QString description(void) const
void slotSiteSelected(MythUIButtonListItem *item)
@ kSimplify
Do Today/Yesterday/Tomorrow transform.
void ShowEditDialog(bool edit)
std::vector< NewsArticle > List
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
MythUIImage * m_thumbnailImage
virtual void SetText(const QString &text)
static const Type kEventType
MythMainWindow * GetMythMainWindow(void)
bool Create(void) override
std::chrono::minutes m_updateFreq
MythScreenStack * GetStack(const QString &Stackname)
QString enclosure(void) const
std::chrono::minutes m_timerTimeout
@ kDateTimeFull
Default local time.
MythUIButtonList * m_sitesList
@ kMSDontDisableDrawing
avoid disabling UI drawing
void AllowInput(bool Allow)
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
bool IsVisible(bool recurse=false) const
MythUIImage * m_enclosureImage
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.