aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder
diff options
context:
space:
mode:
authorKen Moore <moorekou@gmail.com>2016-06-01 14:45:20 -0400
committerKen Moore <moorekou@gmail.com>2016-06-01 14:45:20 -0400
commit23c4c6c217363c0ea7772e312d2c9e0f8ff78e78 (patch)
tree4f04cebed95739516ebc13b43a7a33c388972925 /src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder
parentAdd the beginnings of a new desktop plugin: rssreader (diff)
downloadlumina-23c4c6c217363c0ea7772e312d2c9e0f8ff78e78.tar.gz
lumina-23c4c6c217363c0ea7772e312d2c9e0f8ff78e78.tar.bz2
lumina-23c4c6c217363c0ea7772e312d2c9e0f8ff78e78.zip
Get the new RSS reader plugin mostly-functional. Add/remove feeds seems to work, as well as the main feed display. Still need the feed/channel info page populated though.
Diffstat (limited to 'src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder')
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.cpp135
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.h4
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.ui12
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.cpp191
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.h30
5 files changed, 314 insertions, 58 deletions
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.cpp
index d4a9aa44..0bfc090e 100644
--- a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.cpp
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.cpp
@@ -19,6 +19,7 @@ RSSFeedPlugin::RSSFeedPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID)
ui->setupUi(this);
//Load the global settings
setprefix = "rssreader/"; //this structure/prefix should be used for *all* plugins of this type
+ RSS = new RSSReader(this, setprefix);
//Create the options menu
optionsMenu = new QMenu(this);
@@ -28,10 +29,23 @@ RSSFeedPlugin::RSSFeedPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID)
connect(ui->push_back2, SIGNAL(clicked()), this, SLOT(backToFeeds()) );
connect(ui->push_back3, SIGNAL(clicked()), this, SLOT(backToFeeds()) );
connect(ui->push_save_settings, SIGNAL(clicked()), this, SLOT(saveSettings()) );
-
+ connect(RSS, SIGNAL(rssChanged(QString)), this, SLOT(RSSItemChanged(QString)) );
+ connect(RSS, SIGNAL(newChannelsAvailable()), this, SLOT(UpdateFeedList()));
+ connect(ui->tool_gotosite, SIGNAL(clicked()), this, SLOT(openFeedPage()) );
+ connect(ui->push_rm_feed, SIGNAL(clicked()), this, SLOT(removeFeed()) );
+ connect(ui->push_add_url, SIGNAL(clicked()), this, SLOT(addNewFeed()) );
updateOptionsMenu();
QTimer::singleShot(0,this, SLOT(loadIcons()) );
//qDebug() << " - Done with init";
+ QStringList feeds;
+ if( !LSession::handle()->DesktopPluginSettings()->contains(setprefix+"currentfeeds") ){
+ //First-time run of the plugin - automatically load the default feeds
+ feeds << "http://lumina-desktop.org/?feed=rss2"; //Lumina Desktop blog feed
+ LSession::handle()->DesktopPluginSettings()->setValue(setprefix+"currentfeeds", feeds);
+ }else{
+ feeds = LSession::handle()->DesktopPluginSettings()->value(setprefix+"currentfeeds",QStringList()).toStringList();
+ }
+ RSS->addUrls(feeds);
}
RSSFeedPlugin::~RSSFeedPlugin(){
@@ -47,16 +61,36 @@ void RSSFeedPlugin::updateOptionsMenu(){
optionsMenu->addAction(LXDG::findIcon("help-about",""), tr("View Feed Details"), this, SLOT(openFeedInfo()) );
optionsMenu->addAction(LXDG::findIcon("configure",""), tr("Settings"), this, SLOT(openSettings()) );
optionsMenu->addSeparator();
- optionsMenu->addAction(LXDG::findIcon("download",""), tr("Update Feeds Now"), this, SLOT(resync()) );
+ optionsMenu->addAction(LXDG::findIcon("download",""), tr("Update Feeds Now"), this, SLOT(resyncFeeds()) );
}
//Simplification functions for loading feed info onto widgets
void RSSFeedPlugin::updateFeed(QString ID){
-
+ //Save the datetime this feed was read
+ LSession::handle()->DesktopPluginSettings()->setValue(setprefix+"feedReads/"+ID, QDateTime::currentDateTime() );
+
+ //Now clear/update the feed viewer (HTML)
+ ui->text_feed->clear();
+ QString html;
+ RSSchannel data = RSS->dataForID(ID);
+ ui->label_lastupdate->setText( data.lastsync.toString(Qt::DefaultLocaleShortDate) );
+ // - generate the html
+ // html.append("<ul style=\"margin-left: 3px;\">\n");
+ for(int i=0; i<data.items.length(); i++){
+ //html.append("<li>");
+ html.append("<h3><a href=\""+data.items[i].link+"\">"+data.items[i].title+"</a></h3>");
+ if(!data.items[i].pubdate.isNull()){html.append("<i>("+data.items[i].pubdate.toString(Qt::DefaultLocaleShortDate)+")</i><br>"); }
+ html.append(data.items[i].description);
+ //html.append("</li>\n");
+ if(i+1 < data.items.length()){ html.append("<br>"); }
+ }
+ //html.append("</ul>\n");
+ // - load that html into the viewer
+ ui->text_feed->setHtml(html);
}
void RSSFeedPlugin::updateFeedInfo(QString ID){
-
+ ui->page_feed_info->setWhatsThis(ID);
}
//================
@@ -80,6 +114,9 @@ void RSSFeedPlugin::backToFeeds(){
}
void RSSFeedPlugin::openFeedInfo(){
+ QString ID = ui->combo_feed->currentData().toString();
+ if(ID.isEmpty()){ return; }
+ updateFeedInfo(ID);
ui->stackedWidget->setCurrentWidget(ui->page_feed_info);
}
@@ -113,12 +150,16 @@ void RSSFeedPlugin::addNewFeed(){
ui->line_new_url->setFocus();
return;
}
+ //Add the URL to the settings file for next login
+ QStringList feeds = LSession::handle()->DesktopPluginSettings()->value(setprefix+"currentfeeds",QStringList()).toStringList();
+ feeds << url.toString();
+ LSession::handle()->DesktopPluginSettings()->setValue(setprefix+"currentfeeds", feeds);
//Set this URL as the current selection
ui->combo_feed->setWhatsThis(url.toString()); //hidden field - will trigger an update in a moment
//Add the URL to the backend
-
- UpdateFeedList(); //now re-load the feeds which are available
+ RSS->addUrls(QStringList() << url.toString());
+ //UpdateFeedList(); //now re-load the feeds which are available
//Now go back to the main page
backToFeeds();
@@ -128,27 +169,38 @@ void RSSFeedPlugin::removeFeed(){
QString ID = ui->page_feed_info->whatsThis();
if(ID.isEmpty()){ return; }
//Remove from the RSS feed object
-
- //Update the feed list
- UpdateFeedList(); //now re-load the feeds which are available
+ RSS->removeUrl(ID);
+ //Remove the URL from the settings file for next login
+ QStringList feeds = LSession::handle()->DesktopPluginSettings()->value(setprefix+"currentfeeds",QStringList()).toStringList();
+ feeds.removeAll(ID);
+ LSession::handle()->DesktopPluginSettings()->setValue(setprefix+"currentfeeds", feeds);
//Now go back to the main page
backToFeeds();
}
+void RSSFeedPlugin::resyncFeeds(){
+ RSS->addUrls( LSession::handle()->DesktopPluginSettings()->value(setprefix+"currentfeeds",QStringList()).toStringList() );
+ RSS->syncNow();
+}
+
// - Feed Interactions
void RSSFeedPlugin::currentFeedChanged(){
QString ID = ui->combo_feed->currentData().toString();
if(ID.isEmpty()){ return; } //no feed selected
+ //Remove the "unread" color from the feed
+ ui->combo_feed->setItemData( ui->combo_feed->currentIndex(), QBrush(Qt::transparent) , Qt::BackgroundRole);
+ updateFeed(ID);
}
void RSSFeedPlugin::openFeedPage(){ //Open main website for feed
QString ID = ui->combo_feed->currentData().toString();
//Find the data associated with this feed
- QString url;
-
+ RSSchannel data = RSS->dataForID(ID);
+ QString url = data.link;
+ qDebug() << "Open Feed Page:" << url;
//Now launch the browser
if(!url.isEmpty()){
- QProcess::startDetached("lumina-open \""+url+"\"");
+ LSession::LaunchApplication("lumina-open \""+url+"\"");
}
}
@@ -159,7 +211,6 @@ void RSSFeedPlugin::saveSettings(){
if(ui->combo_sync_units->currentIndex()==1){ DI = DI*60; } //convert from hours to minutes
set->setValue(setprefix+"default_interval_minutes", DI);
set->sync();
- //Now prod the feed object that something changed
//Now go back to the feeds
backToFeeds();
@@ -167,12 +218,66 @@ void RSSFeedPlugin::saveSettings(){
//Feed Object interactions
void RSSFeedPlugin::UpdateFeedList(){
-
+
+ QString activate = ui->combo_feed->whatsThis();
+ if(!activate.isEmpty()){ ui->combo_feed->setWhatsThis(""); }
+ if(activate.isEmpty()){ activate = ui->combo_feed->currentData().toString(); } // keep current item selected
+ //Now get/list all the available feeds
+ QStringList IDS = RSS->channels(); //this is pre-sorted by title of the feed
+ //qDebug() << "Update RSS Feed List:" << IDS << activate;
+ for(int i=0; i<IDS.length(); i++){
+ bool newitem = false;
+ if(ui->combo_feed->count()<=i){ newitem = true; }
+ else{
+ QString cid = ui->combo_feed->itemData(i).toString();
+ if(IDS[i]!=cid){
+ if(IDS.contains(cid)){ newitem = true; } //this item is just out of order
+ else{ ui->combo_feed->removeItem(i); } //item no longer is valid
+ }
+ }
+ if(newitem){
+ //Need to add a new item at this point in the menu
+ RSSchannel info = RSS->dataForID(IDS[i]);
+ if(info.title.isEmpty()){
+ //invalid/empty channel
+ ui->combo_feed->insertItem(i, IDS[i], IDS[i]); //just show the URL
+ }else{
+ ui->combo_feed->insertItem(i, info.icon, info.title, IDS[i]);
+ }
+ }
+ }
+ //Remove any extra items on the end of the list
+ for(int i=IDS.length(); i<ui->combo_feed->count(); i++){
+ ui->combo_feed->removeItem(i); i--;
+ }
+ //Now activate the proper item as needed
+ if(IDS.contains(activate)){
+ ui->combo_feed->setCurrentIndex( IDS.indexOf(activate) );
+ }
}
void RSSFeedPlugin::RSSItemChanged(QString ID){
-
+ for(int i=0; i<ui->combo_feed->count(); i++){
+ if(ui->combo_feed->itemData(i).toString()!=ID){ continue; }
+ RSSchannel info = RSS->dataForID(ID);
+ if(info.title.isEmpty()){
+ ui->combo_feed->setItemText(i, ID);
+ ui->combo_feed->setItemIcon(i, LXDG::findIcon("dialog-cancel","") );
+ }else{
+ ui->combo_feed->setItemText(i, info.title);
+ ui->combo_feed->setItemIcon(i, info.icon );
+ QColor color(Qt::transparent);
+ if( info.lastBuildDate > LSession::handle()->DesktopPluginSettings()->value(setprefix+"feedReads/"+ID,QDateTime()).toDateTime() ){
+ color = QColor(255,10,10,100); //semi-transparent red
+ }
+ ui->combo_feed->setItemData(i, QBrush(color) , Qt::BackgroundRole);
+ }
+ }
+ if(ID == ui->combo_feed->currentData().toString()){
+ currentFeedChanged(); //re-load the current feed
+ }
}
+
//==================
// PUBLIC SLOTS
//==================
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.h b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.h
index a29e5ec1..ea6ee5e7 100644
--- a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.h
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.h
@@ -12,6 +12,8 @@
#include <QTimer>
#include "../LDPlugin.h"
+#include "RSSObjects.h"
+
namespace Ui{
class RSSFeedPlugin;
};
@@ -30,6 +32,7 @@ private:
Ui::RSSFeedPlugin *ui;
QMenu *optionsMenu;
QString setprefix; //settings prefix
+ RSSReader *RSS;
void updateOptionsMenu();
@@ -49,6 +52,7 @@ private slots:
// - Feed Management
void addNewFeed(); // the "add" button (current url in widget on page)
void removeFeed(); // the "remove" button (current feed for page)
+ void resyncFeeds();
// - Feed Interactions
void currentFeedChanged();
void openFeedPage(); //Open the website in a browser
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.ui b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.ui
index d9972473..7689e88b 100644
--- a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.ui
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.ui
@@ -102,7 +102,7 @@
</layout>
</item>
<item>
- <widget class="QTextEdit" name="text_feed">
+ <widget class="QTextBrowser" name="text_feed">
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
@@ -119,6 +119,12 @@ p, li { white-space: pre-wrap; }
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ <property name="openLinks">
+ <bool>true</bool>
+ </property>
</widget>
</item>
</layout>
@@ -191,8 +197,8 @@ p, li { white-space: pre-wrap; }
<rect>
<x>0</x>
<y>0</y>
- <width>228</width>
- <height>178</height>
+ <width>100</width>
+ <height>30</height>
</rect>
</property>
</widget>
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.cpp
index 45a6bfeb..f525d19c 100644
--- a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.cpp
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.cpp
@@ -8,11 +8,20 @@
#include <QNetworkRequest>
#include <QXmlStreamReader>
+#include "LSession.h"
+
//============
// PUBLIC
//============
-RSSReader::RSSReader(QObject *parent) : QObject(parent){
+RSSReader::RSSReader(QObject *parent, QString settingsPrefix) : QObject(parent){
NMAN = new QNetworkAccessManager(this);
+ connect(NMAN, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)) );
+
+ setprefix = settingsPrefix;
+ syncTimer = new QTimer(this);
+ syncTimer->setInterval(300000); //5 minutes
+ connect(syncTimer, SIGNAL(timeout()), this, SLOT(checkTimes()));
+ syncTimer->start();
}
RSSReader::~RSSReader(){
@@ -21,81 +30,201 @@ RSSReader::~RSSReader(){
//Information retrieval
QStringList RSSReader::channels(){
- return QStringList( data.keys() );
+ QStringList urls = hash.keys();
+ QStringList ids;
+ //sort all the channels by title before output
+ for(int i=0; i<urls.length(); i++){
+ QString title = hash[urls[i]].title;
+ if(title.isEmpty()){ title = "ZZZ"; } //put currently-invalid ones at the end of the list
+ ids << title+" : "+urls[i];
+ }
+ ids.sort();
+ //Now strip off all the titles again to just get the IDs
+ for(int i=0; i<ids.length(); i++){
+ ids[i] = ids[i].section(" : ",-1);
+ }
+ return ids;
}
-Rsschannel RSSReader::dataForID(QString ID){
-
+RSSchannel RSSReader::dataForID(QString ID){
+ if(hash.contains(ID)){ return hash[ID]; }
+ else{ return RSSchannel(); }
}
//Initial setup
-void RSSReader::addUrls(){
-
+void RSSReader::addUrls(QStringList urls){
+ //qDebug() << "Add URLS:" << urls;
+ for(int i=0; i<urls.length(); i++){
+ //Note: Make sure we get the complete URL form for accurate comparison later
+ QString url = QUrl(urls[i]).toString();
+ if(hash.contains(url)){ continue; } //already handled
+ hash.insert(url, RSSchannel()); //put an empty struct into the hash for now
+ requestRSS(url); //startup the initial request for this url
+ }
+ emit newChannelsAvailable();
}
void RSSReader::removeUrl(QString ID){
-
+ if(hash.contains(ID)){ hash.remove(ID); }
+ emit newChannelsAvailable();
}
//=================
// PUBLIC SLOTS
//=================
void RSSReader::syncNow(){
-
+ QStringList urls = hash.keys();
+ for(int i=0; i<urls.length(); i++){
+ requestRSS(urls[i]);
+ }
}
//=================
// PRIVATE
//=================
-void RSSchannel::requestRSS(QString url){
- NMAN->get( QNetworkRequest( QUrl(url) ) );
+void RSSReader::requestRSS(QString url){
+ if(!outstandingURLS.contains(url)){
+ //qDebug() << "Request URL:" << url;
+ NMAN->get( QNetworkRequest( QUrl(url) ) );
+ outstandingURLS << url;
+ }
}
//RSS parsing functions
-RSSchannel RSSReader::readRSS(QIODevice *device){
- QXmlStreamReader xml(device);
+RSSchannel RSSReader::readRSS(QByteArray bytes){
+ //Note: We could expand this later to support multiple "channel"s per Feed
+ // but it seems like there is normally only one channel anyway
+ //qDebug() << "Read RSS:" << bytes;
+ QXmlStreamReader xml(bytes);
RSSchannel rssinfo;
+ //qDebug() << "Can Read XML Stream:" << !xml.hasError();
+ if(xml.hasError()){ qDebug() << " - Error String:" << xml.errorString(); }
if(xml.readNextStartElement()){
- if(xml.name() = "rss" && xml.attributes().value("version" =="2.0")){
+ //qDebug() << " - RSS Element:" << xml.name();
+ if(xml.name() == "rss" && xml.attributes().value("version") =="2.0"){
while(xml.readNextStartElement()){
if(xml.name()=="channel"){ rssinfo = readRSSChannel(&xml); }
+ else{ xml.skipCurrentElement(); }
}
}
}
+ if(xml.hasError()){ qDebug() << " - Error String:" << xml.errorString(); }
return rssinfo;
}
RSSchannel RSSReader::readRSSChannel(QXmlStreamReader *rss){
RSSchannel info;
- while(rss.readNextStartElement()){
- if(rss.name()=="item"){ info.items << readRSSItem(rss); }
- else if(rss.name()=="title"){ info.title = rss.readElementText(); }
- else if(rss.name()=="link"){ info.link = rss.readElementText(); }
- else if(rss.name()=="description"){ info.description = rss.readElementText(); }
- else if(rss.name()=="lastBuildDate"){ info.lastBuildDate = RSSDateTime(rss.readElementText()); }
- else if(rss.name()=="pubDate"){ info.lastPubDate = RSSDateTime(rss.readElementText()); }
- else if(rss.name()=="image"){ info.link = rss.readElementText(); }
- else if(rss.name()=="guid"){ info.guid = rss.readElementText(); }
- //else if(rss.name()=="skipHours"){ info.link = rss.readElementText(); }
- //else if(rss.name()=="skipDays"){ info.link = rss.readElementText(); }
- else if(rss.name()=="ttl"){ info.timetolive = rss.readElementText().toInt(); }
+ info.timetolive = -1;
+ while(rss->readNextStartElement()){
+ //qDebug() << " - RSS Element (channel):" <<rss->name();
+ if(rss->name()=="item"){ info.items << readRSSItem(rss); }
+ else if(rss->name()=="title"){ info.title = rss->readElementText(); }
+ else if(rss->name()=="link"){ info.link = rss->readElementText(); }
+ else if(rss->name()=="description"){ info.description = rss->readElementText(); }
+ else if(rss->name()=="lastBuildDate"){ info.lastBuildDate = RSSDateTime(rss->readElementText()); }
+ else if(rss->name()=="pubDate"){ info.lastPubDate = RSSDateTime(rss->readElementText()); }
+ else if(rss->name()=="image"){ readRSSImage(&info, rss); }
+ //else if(rss->name()=="skipHours"){ info.link = rss->readElementText(); }
+ //else if(rss->name()=="skipDays"){ info.link = rss->readElementText(); }
+ else if(rss->name()=="ttl"){ info.timetolive = rss->readElementText().toInt(); }
+ else{ rss->skipCurrentElement(); }
}
return info;
}
+
RSSitem RSSReader::readRSSItem(QXmlStreamReader *rss){
-
+ RSSitem item;
+ while(rss->readNextStartElement()){
+ //qDebug() << " - RSS Element (Item):" << rss->name();
+ if(rss->name()=="title"){ item.title = rss->readElementText(); }
+ else if(rss->name()=="link"){ item.link = rss->readElementText(); }
+ else if(rss->name()=="description"){ item.description = rss->readElementText(); }
+ else if(rss->name()=="comments"){ item.comments_url = rss->readElementText(); }
+ else if(rss->name()=="author"){
+ //Special handling - this field can contain both email and name
+ QString raw = rss->readElementText();
+ if(raw.contains("@")){
+ item.author_email = raw.split(" ").filter("@").first();
+ item.author = raw.remove(item.author_email).remove("(").remove(")").simplified(); //the name is often put within parentheses after the email
+ }else{ item.author = raw; }
+ }
+ else if(rss->name()=="guid"){ item.guid = rss->readElementText(); }
+ else if(rss->name()=="pubDate"){ item.pubdate = RSSDateTime(rss->readElementText()); }
+ else{ rss->skipCurrentElement(); }
+ }
+ return item;
}
-QDateTime RSSReader::RSSDateTime(QString datetime){
+void RSSReader::readRSSImage(RSSchannel *item, QXmlStreamReader *rss){
+ while(rss->readNextStartElement()){
+ //qDebug() << " - RSS Element (Image):" << rss->name();
+ if(rss->name()=="url"){ item->icon_url = rss->readElementText(); }
+ else if(rss->name()=="title"){ item->icon_title = rss->readElementText(); }
+ else if(rss->name()=="link"){ item->icon_link = rss->readElementText(); }
+ else if(rss->name()=="width"){ item->icon_size.setWidth(rss->readElementText().toInt()); }
+ else if(rss->name()=="height"){ item->icon_size.setHeight(rss->readElementText().toInt()); }
+ else if(rss->name()=="description"){ item->icon_description = rss->readElementText(); }
+ }
+ //Go ahead and kick off the request for the icon
+ if(!item->icon_url.isEmpty()){ requestRSS(item->icon_url); }
+}
+QDateTime RSSReader::RSSDateTime(QString datetime){
+ return QDateTime::fromString(datetime, Qt::RFC2822Date);
}
//=================
// PRIVATE SLOTS
//=================
void RSSReader::replyFinished(QNetworkReply *reply){
- RSSchannel info = ReadRSS(reply); //QNetworkReply can be used as QIODevice
- reply->deleteLater(); //clean up
- //Validate the info and announce any changes
-
+ QString url = reply->request().url().toString();
+ //qDebug() << "Got Reply:" << url;
+ QByteArray data = reply->readAll();
+ outstandingURLS.removeAll(url);
+ if(!hash.contains(url)){
+ //qDebug() << " - hash does not contain URL!!";
+ //URL removed from list while a request was outstanding?
+ //Could also be an icon fetch response
+ QStringList keys = hash.keys();
+ for(int i=0; i<keys.length(); i++){
+ if(hash[keys[i]].icon_url == url){
+ //Icon fetch response
+ RSSchannel info = hash[keys[i]];
+ QByteArray bytes = reply->readAll();
+ QImage img = QImage::fromData(bytes);
+ info.icon = QIcon( QPixmap::fromImage(img) );
+ qDebug() << "Got Icon response:" << url << bytes;
+ qDebug() << info.icon;
+ hash.insert(keys[i], info); //insert back into the hash
+ emit rssChanged(keys[i]);
+ break;
+ }
+ }
+ reply->deleteLater();
+ }else{
+ //RSS reply
+ RSSchannel info = readRSS(data); //QNetworkReply can be used as QIODevice
+ reply->deleteLater(); //clean up
+ //Validate the info and announce any changes
+ if(info.title.isEmpty() || info.link.isEmpty() || info.description.isEmpty()){ return; } //bad info/read
+ //Update the bookkeeping elements of the info
+ if(info.timetolive<=0){ info.timetolive = LSession::handle()->DesktopPluginSettings()->value(setprefix+"default_interval_minutes", 60).toInt(); }
+ if(info.timetolive <=0){ info.timetolive = 60; } //error in integer conversion from settings?
+ info.lastsync = QDateTime::currentDateTime(); info.nextsync = info.lastsync.addSecs(info.timetolive * 60);
+ //Now see if anything changed and save the info into the hash
+ bool changed = (hash[url].lastBuildDate.isNull() || (hash[url].lastBuildDate < info.lastBuildDate) );
+ bool newinfo = false;
+ if(changed){ newinfo = hash[url].title.isEmpty(); } //no previous info from this URL
+ hash.insert(url, info);
+ if(newinfo){ emit newChannelsAvailable(); } //new channel
+ else if(changed){ emit rssChanged(url); } //update to existing channel
+ }
+}
+void RSSReader::checkTimes(){
+ if(LSession::handle()->DesktopPluginSettings()->value(setprefix+"manual_sync_only", false).toBool()){ return; }
+ QStringList urls = hash.keys();
+ QDateTime cdt = QDateTime::currentDateTime();
+ for(int i=0; i<urls.length(); i++){
+ if(hash[urls[i]].nextsync < cdt){ requestRSS(urls[i]); }
+ }
}
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.h b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.h
index a1cffc3f..82ad9f86 100644
--- a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.h
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.h
@@ -13,6 +13,8 @@
#include <QDateTime>
#include <QList>
#include <QIcon>
+#include <QTimer>
+#include <QXmlStreamReader> //Contained in the Qt "core" module - don't need the full "xml" module for this
struct RSSitem{
//Required Fields
@@ -36,47 +38,57 @@ struct RSSchannel{
//QStringList skipdays;
// - icon info
QIcon icon;
- QString iconurl, icontitle, iconlink;
- QSize iconsize;
+ QString icon_url, icon_title, icon_link, icon_description;
+ QSize icon_size;
//All items within this channel
QList<RSSitem> items;
//Optional RSS2 elements ignored:
// "cloud", "textInput", "rating", "language", "copyright", "managingEditor", "webMaster",
// "category", "generator", "docs"
+
+ //Internal data for bookkeeping
+ QDateTime lastsync, nextsync;
};
class RSSReader : public QObject{
Q_OBJECT
public:
- RSSReader(QObject *parent);
+ RSSReader(QObject *parent, QString settingsPrefix);
~RSSReader();
//Information retrieval
QStringList channels(); //returns all ID's
- Rsschannel dataForID(QString ID);
+ RSSchannel dataForID(QString ID);
//Initial setup
- void addUrls();
+ void addUrls(QStringList urls);
void removeUrl(QString ID);
public slots:
void syncNow(); //not generally needed
private:
- QHash<QString, RSSchannel> data; // ID/data
- //Network request functions
+ //Internal data objects
+ QHash<QString, RSSchannel> hash; // ID/data
+ QString setprefix;
+ QTimer *syncTimer;
QNetworkAccessManager *NMAN;
+ QStringList outstandingURLS;
+
+ //Network request function
void requestRSS(QString url);
//RSS parsing functions
- RSSchannel readRSS(QByteArray rss);
- RSSchannel readRSSChannel(QXmlStreamReader *rss)
+ RSSchannel readRSS(QByteArray bytes);
+ RSSchannel readRSSChannel(QXmlStreamReader *rss);
RSSitem readRSSItem(QXmlStreamReader *rss);
+ void readRSSImage(RSSchannel *item, QXmlStreamReader *rss);
QDateTime RSSDateTime(QString datetime);
private slots:
void replyFinished(QNetworkReply *reply);
+ void checkTimes();
signals:
void rssChanged(QString); //ID
bgstack15