From 0e378ef4f087a04e4cc3643eb533f2e59e1a9061 Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Tue, 31 May 2016 15:49:42 -0400 Subject: Add the beginnings of a new desktop plugin: rssreader This is a simple RSS reader for the desktop. (Not finished yet - but getting close). --- .../desktop-plugins/rssfeeder/RSSFeedPlugin.cpp | 186 ++++++++ .../desktop-plugins/rssfeeder/RSSFeedPlugin.h | 66 +++ .../desktop-plugins/rssfeeder/RSSFeedPlugin.ui | 523 +++++++++++++++++++++ .../desktop-plugins/rssfeeder/RSSObjects.cpp | 101 ++++ .../desktop-plugins/rssfeeder/RSSObjects.h | 86 ++++ 5 files changed, 962 insertions(+) create mode 100644 src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.cpp create mode 100644 src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.h create mode 100644 src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.ui create mode 100644 src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.cpp create mode 100644 src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.h (limited to 'src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder') diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.cpp new file mode 100644 index 00000000..d4a9aa44 --- /dev/null +++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.cpp @@ -0,0 +1,186 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2016, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "RSSFeedPlugin.h" +#include "ui_RSSFeedPlugin.h" + +#include +#include "LSession.h" +#include +#include +#include +#include +#include + +RSSFeedPlugin::RSSFeedPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID), ui(new Ui::RSSFeedPlugin()){ + ui->setupUi(this); + //Load the global settings + setprefix = "rssreader/"; //this structure/prefix should be used for *all* plugins of this type + + //Create the options menu + optionsMenu = new QMenu(this); + ui->tool_options->setMenu(optionsMenu); + //Setup any signal/slot connections + connect(ui->push_back1, SIGNAL(clicked()), this, SLOT(backToFeeds()) ); + 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()) ); + + updateOptionsMenu(); + QTimer::singleShot(0,this, SLOT(loadIcons()) ); + //qDebug() << " - Done with init"; +} + +RSSFeedPlugin::~RSSFeedPlugin(){ + +} + +//================ +// PRIVATE +//================ +void RSSFeedPlugin::updateOptionsMenu(){ + optionsMenu->clear(); + optionsMenu->addAction(LXDG::findIcon("list-add",""), tr("Add RSS Feed"), this, SLOT(openFeedNew()) ); + 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()) ); +} + +//Simplification functions for loading feed info onto widgets +void RSSFeedPlugin::updateFeed(QString ID){ + +} + +void RSSFeedPlugin::updateFeedInfo(QString ID){ + +} + +//================ +// PRIVATE SLOTS +//================ +void RSSFeedPlugin::loadIcons(){ + ui->tool_options->setIcon( LXDG::findIcon("configure","") ); + ui->tool_gotosite->setIcon( LXDG::findIcon("applications-internet","") ); + ui->push_back1->setIcon( LXDG::findIcon("go-previous","") ); + ui->push_back2->setIcon( LXDG::findIcon("go-previous","") ); + ui->push_back3->setIcon( LXDG::findIcon("go-previous","") ); + ui->push_rm_feed->setIcon( LXDG::findIcon("list-remove","") ); + ui->push_add_url->setIcon( LXDG::findIcon("list-add","") ); + ui->push_save_settings->setIcon( LXDG::findIcon("document-save","") ); +} + +//GUI slots +// - Page management +void RSSFeedPlugin::backToFeeds(){ + ui->stackedWidget->setCurrentWidget(ui->page_feed); +} + +void RSSFeedPlugin::openFeedInfo(){ + ui->stackedWidget->setCurrentWidget(ui->page_feed_info); + +} + +void RSSFeedPlugin::openFeedNew(){ + ui->line_new_url->setText(""); + ui->stackedWidget->setCurrentWidget(ui->page_new_feed); +} + +void RSSFeedPlugin::openSettings(){ + //Sync the widget with the current settings + QSettings *set = LSession::handle()->DesktopPluginSettings(); + + ui->check_manual_sync->setChecked( set->value(setprefix+"manual_sync_only", false).toBool() ); + int DI = set->value(setprefix+"default_interval_minutes", 60).toInt(); + if(DI<1){ DI = 60; } + if( (DI%60) == 0 ){DI = DI/60; ui->combo_sync_units->setCurrentIndex(1); } //hourly setting + else{ ui->combo_sync_units->setCurrentIndex(1); } //minutes setting + ui->spin_synctime->setValue(DI); + + //Now show the page + ui->stackedWidget->setCurrentWidget(ui->page_settings); +} + +// - Feed Management +void RSSFeedPlugin::addNewFeed(){ + if(ui->line_new_url->text().isEmpty()){ return; } //nothing to add + //Validate the URL + QUrl url(ui->line_new_url->text()); + if(!url.isValid()){ + ui->line_new_url->setFocus(); + return; + } + + //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 + + //Now go back to the main page + backToFeeds(); +} + +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 + //Now go back to the main page + backToFeeds(); +} + +// - Feed Interactions +void RSSFeedPlugin::currentFeedChanged(){ + QString ID = ui->combo_feed->currentData().toString(); + if(ID.isEmpty()){ return; } //no feed selected +} + +void RSSFeedPlugin::openFeedPage(){ //Open main website for feed + QString ID = ui->combo_feed->currentData().toString(); + //Find the data associated with this feed + QString url; + + //Now launch the browser + if(!url.isEmpty()){ + QProcess::startDetached("lumina-open \""+url+"\""); + } +} + +void RSSFeedPlugin::saveSettings(){ + QSettings *set = LSession::handle()->DesktopPluginSettings(); + set->setValue(setprefix+"manual_sync_only", ui->check_manual_sync->isChecked() ); + int DI = ui->spin_synctime->value(); + 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(); +} + +//Feed Object interactions +void RSSFeedPlugin::UpdateFeedList(){ + +} + +void RSSFeedPlugin::RSSItemChanged(QString ID){ + +} +//================== +// PUBLIC SLOTS +//================== +void RSSFeedPlugin::LocaleChange(){ + ui->retranslateUi(this); + updateOptionsMenu(); +} +void RSSFeedPlugin::ThemeChange(){ + QTimer::singleShot(0,this, SLOT(loadIcons())); + updateOptionsMenu(); +} diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.h b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.h new file mode 100644 index 00000000..a29e5ec1 --- /dev/null +++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.h @@ -0,0 +1,66 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2016, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// This plugin is a simple RSS feed reader for the desktop +//=========================================== +#ifndef _LUMINA_DESKTOP_RSS_FEEDER_PLUGIN_H +#define _LUMINA_DESKTOP_RSS_FEEDER_PLUGIN_H + +#include +#include "../LDPlugin.h" + +namespace Ui{ + class RSSFeedPlugin; +}; + +class RSSFeedPlugin : public LDPlugin{ + Q_OBJECT +public: + RSSFeedPlugin(QWidget* parent, QString ID); + ~RSSFeedPlugin(); + + virtual QSize defaultPluginSize(){ + // The returned QSize is in grid points (typically 100 or 200 pixels square) + return QSize(3,3); + } +private: + Ui::RSSFeedPlugin *ui; + QMenu *optionsMenu; + QString setprefix; //settings prefix + + void updateOptionsMenu(); + + //Simplification functions for loading feed info onto widgets + void updateFeed(QString ID); + void updateFeedInfo(QString ID); + +private slots: + void loadIcons(); + + //GUI slots + // - Page management + void backToFeeds(); + void openFeedInfo(); + void openFeedNew(); + void openSettings(); + // - Feed Management + void addNewFeed(); // the "add" button (current url in widget on page) + void removeFeed(); // the "remove" button (current feed for page) + // - Feed Interactions + void currentFeedChanged(); + void openFeedPage(); //Open the website in a browser + void saveSettings(); + + //Feed Object interactions + void UpdateFeedList(); + void RSSItemChanged(QString ID); + +public slots: + void LocaleChange(); + void ThemeChange(); + +}; +#endif diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.ui b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.ui new file mode 100644 index 00000000..d9972473 --- /dev/null +++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSFeedPlugin.ui @@ -0,0 +1,523 @@ + + + RSSFeedPlugin + + + + 0 + 0 + 238 + 278 + + + + Form + + + + 0 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + 0 + + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + View Options + + + + + + QToolButton::InstantPopup + + + true + + + + + + + + + + + + + + + + + + Open Website + + + More + + + true + + + Qt::NoArrow + + + + + + + + + false + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 5 + + + + + + + Back to Feeds + + + + + + + + + + 0 + 0 + + + + Feed Information + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + true + + + + + 0 + 0 + 228 + 178 + + + + + + + + + + + + + + Remove Feed + + + + + + + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Back to Feeds + + + + + + + + + + 0 + 0 + + + + New Feed Subscription + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + RSS URL + + + Qt::AlignCenter + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add to Feeds + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Back to Feeds + + + + + + + + + + 0 + 0 + + + + Feed Reader Settings + + + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + Manual Sync Only + + + + + + + Some RSS feeds may request custom update intervals instead of using this setting + + + Default Sync Interval + + + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + 1 + + + 60 + + + + + + + Hour(s) + + + 1 + + + + Minutes + + + + + Hour(s) + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Save Settings + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + + diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.cpp new file mode 100644 index 00000000..45a6bfeb --- /dev/null +++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.cpp @@ -0,0 +1,101 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2016, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "RSSObjects.h" +#include +#include + +//============ +// PUBLIC +//============ +RSSReader::RSSReader(QObject *parent) : QObject(parent){ + NMAN = new QNetworkAccessManager(this); +} + +RSSReader::~RSSReader(){ + +} + +//Information retrieval +QStringList RSSReader::channels(){ + return QStringList( data.keys() ); +} + +Rsschannel RSSReader::dataForID(QString ID){ + +} + +//Initial setup +void RSSReader::addUrls(){ + +} + +void RSSReader::removeUrl(QString ID){ + +} + +//================= +// PUBLIC SLOTS +//================= +void RSSReader::syncNow(){ + +} + +//================= +// PRIVATE +//================= +void RSSchannel::requestRSS(QString url){ + NMAN->get( QNetworkRequest( QUrl(url) ) ); +} + +//RSS parsing functions +RSSchannel RSSReader::readRSS(QIODevice *device){ + QXmlStreamReader xml(device); + RSSchannel rssinfo; + if(xml.readNextStartElement()){ + if(xml.name() = "rss" && xml.attributes().value("version" =="2.0")){ + while(xml.readNextStartElement()){ + if(xml.name()=="channel"){ rssinfo = readRSSChannel(&xml); } + } + } + } + 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(); } + } + return info; +} +RSSitem RSSReader::readRSSItem(QXmlStreamReader *rss){ + +} + +QDateTime RSSReader::RSSDateTime(QString datetime){ + +} + +//================= +// 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 + + +} diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.h b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.h new file mode 100644 index 00000000..a1cffc3f --- /dev/null +++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssfeeder/RSSObjects.h @@ -0,0 +1,86 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2016, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#ifndef _LUMINA_DESKTOP_RSS_READER_PLUGIN_OBJECT_H +#define _LUMINA_DESKTOP_RSS_READER_PLUGIN_OBJECT_H + +#include +#include +#include +#include +#include +#include + +struct RSSitem{ + //Required Fields + QString title, link, description; + + //Optional Fields + QString comments_url, author_email, author, guid; + QDateTime pubdate; //when the item was published + //IGNORED INFO from RSS2 spec: "category", "source", "enclosure" +}; + +struct RSSchannel{ + //Required fields + QString title, link, description; + + //Optional Fields + QDateTime lastBuildDate, lastPubDate; //last build/publish dates + // - channel refresh information + int timetolive; //in minutes - time until next sync should be performed + //QList skiphours; + //QStringList skipdays; + // - icon info + QIcon icon; + QString iconurl, icontitle, iconlink; + QSize iconsize; + //All items within this channel + QList items; + + //Optional RSS2 elements ignored: + // "cloud", "textInput", "rating", "language", "copyright", "managingEditor", "webMaster", + // "category", "generator", "docs" +}; + +class RSSReader : public QObject{ + Q_OBJECT +public: + RSSReader(QObject *parent); + ~RSSReader(); + + //Information retrieval + QStringList channels(); //returns all ID's + Rsschannel dataForID(QString ID); + + //Initial setup + void addUrls(); + void removeUrl(QString ID); + +public slots: + void syncNow(); //not generally needed + +private: + QHash data; // ID/data + //Network request functions + QNetworkAccessManager *NMAN; + void requestRSS(QString url); + + //RSS parsing functions + RSSchannel readRSS(QByteArray rss); + RSSchannel readRSSChannel(QXmlStreamReader *rss) + RSSitem readRSSItem(QXmlStreamReader *rss); + QDateTime RSSDateTime(QString datetime); + +private slots: + void replyFinished(QNetworkReply *reply); + +signals: + void rssChanged(QString); //ID + void newChannelsAvailable(); +}; + +#endif -- cgit