parent
073f36118b
commit
ec9e6422ff
@ -5,7 +5,8 @@ Added:
|
||||
▪ Auto-update status of feeds is now more general and complete. (issue #91)
|
||||
|
||||
Changed:
|
||||
▪ Better ATOM parsing, respects now XML namespaces, bit better link parsing and other stuff. (issue #104)
|
||||
▪ Updating of RSS Guard now uses GitHub API. (issue #109)
|
||||
▪ Better ATOM/RSS parsing, respects now XML namespaces, bit better link parsing and other stuff. (issue #104)
|
||||
▪ Folder which holds SQL scripts got renamed to "sql".
|
||||
▪ Tweaked some conditions for determining newly "updated" messages in ATOM format. (issue #103)
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<releases>
|
||||
<release version="3.4.0">
|
||||
<url platform="x86" os="Windows">https://github.com/martinrotter/rssguard/releases/download/3.4.0/rssguard-3.4.0-cb15ba92-win32.exe</url>
|
||||
</release>
|
||||
</releases>
|
@ -31,8 +31,7 @@
|
||||
#define URI_SCHEME_FEED_SHORT "feed:"
|
||||
#define URI_SCHEME_FEED "feed://"
|
||||
#define URI_SCHEME_HTTP "http://"
|
||||
#define RELEASES_LIST "https://raw.githubusercontent.com/martinrotter/rssguard/master/resources/text/UPDATES"
|
||||
#define CHANGELOG "https://raw.githubusercontent.com/martinrotter/rssguard/master/resources/text/CHANGELOG"
|
||||
#define RELEASES_LIST "https://api.github.com/repos/martinrotter/rssguard/releases"
|
||||
#define DEFAULT_LOCALE "en"
|
||||
#define DEFAULT_FEED_ENCODING "UTF-8"
|
||||
#define DEFAULT_FEED_TYPE "RSS"
|
||||
|
@ -34,16 +34,25 @@
|
||||
|
||||
|
||||
FormUpdate::FormUpdate(QWidget *parent)
|
||||
: QDialog(parent), m_downloader(nullptr), m_readyToInstall(false), m_ui(new Ui::FormUpdate) {
|
||||
: QDialog(parent), m_downloader(nullptr), m_readyToInstall(false), m_ui(new Ui::FormUpdate), m_lastDownloadedBytes(0) {
|
||||
m_ui->setupUi(this);
|
||||
m_btnUpdate = m_ui->m_buttonBox->addButton(tr("Download update"), QDialogButtonBox::ActionRole);
|
||||
m_btnUpdate->setToolTip(tr("Download new installation files."));
|
||||
m_ui->m_lblCurrentRelease->setText(APP_VERSION);
|
||||
m_ui->m_tabInfo->removeTab(1);
|
||||
|
||||
// Set flags and attributes.
|
||||
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint);
|
||||
setWindowIcon(qApp->icons()->fromTheme(QSL("help-about")));
|
||||
|
||||
if (isSelfUpdateSupported()) {
|
||||
m_btnUpdate = m_ui->m_buttonBox->addButton(tr("Download selected update"), QDialogButtonBox::ActionRole);
|
||||
m_btnUpdate->setToolTip(tr("Download new installation files."));
|
||||
}
|
||||
else {
|
||||
m_btnUpdate = m_ui->m_buttonBox->addButton(tr("Go to application website"), QDialogButtonBox::ActionRole);
|
||||
m_btnUpdate->setToolTip(tr("Go to application website to get update packages manually."));
|
||||
}
|
||||
|
||||
m_btnUpdate->setVisible(false);
|
||||
connect(m_btnUpdate, &QPushButton::clicked, this, &FormUpdate::startUpdate);
|
||||
checkForUpdates();
|
||||
}
|
||||
@ -51,12 +60,8 @@ FormUpdate::FormUpdate(QWidget *parent)
|
||||
FormUpdate::~FormUpdate() {
|
||||
}
|
||||
|
||||
bool FormUpdate::isUpdateForThisSystem() const {
|
||||
return m_updateInfo.m_urls.keys().contains(OS_ID);
|
||||
}
|
||||
|
||||
bool FormUpdate::isSelfUpdateSupported() const {
|
||||
#if defined(Q_OS_WIN)
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
@ -64,51 +69,47 @@ bool FormUpdate::isSelfUpdateSupported() const {
|
||||
}
|
||||
|
||||
void FormUpdate::checkForUpdates() {
|
||||
const QPair<UpdateInfo, QNetworkReply::NetworkError> update = qApp->system()->checkForUpdates();
|
||||
|
||||
m_updateInfo = update.first;
|
||||
const QPair<QList<UpdateInfo>, QNetworkReply::NetworkError> update = qApp->system()->checkForUpdates();
|
||||
|
||||
if (update.second != QNetworkReply::NoError) {
|
||||
m_updateInfo = UpdateInfo();
|
||||
m_ui->m_tabInfo->setEnabled(false);
|
||||
|
||||
//: Unknown release.
|
||||
m_ui->m_lblAvailableRelease->setText(tr("unknown"));
|
||||
m_ui->m_txtChanges->clear();
|
||||
m_ui->m_lblStatus->setStatus(WidgetWithStatus::Error,
|
||||
tr("Error: '%1'.").arg(NetworkFactory::networkErrorText(update.second)),
|
||||
tr("List with updates was not\ndownloaded successfully."));
|
||||
m_btnUpdate->setEnabled(false);
|
||||
m_btnUpdate->setToolTip(tr("Checking for updates failed."));
|
||||
}
|
||||
else {
|
||||
m_ui->m_lblAvailableRelease->setText(update.first.m_availableVersion);
|
||||
m_ui->m_txtChanges->setText(update.first.m_changes);
|
||||
const bool self_update_supported = isSelfUpdateSupported();
|
||||
|
||||
const bool is_self_update_for_this_system = isUpdateForThisSystem() && isSelfUpdateSupported();
|
||||
m_updateInfo = update.first.at(0);
|
||||
m_ui->m_tabInfo->setEnabled(true);
|
||||
m_ui->m_lblAvailableRelease->setText(m_updateInfo.m_availableVersion);
|
||||
m_ui->m_txtChanges->setText(m_updateInfo.m_changes);
|
||||
|
||||
if (SystemFactory::isVersionNewer(update.first.m_availableVersion, APP_VERSION)) {
|
||||
if (SystemFactory::isVersionNewer(m_updateInfo.m_availableVersion, APP_VERSION)) {
|
||||
m_btnUpdate->setVisible(true);
|
||||
m_ui->m_lblStatus->setStatus(WidgetWithStatus::Ok,
|
||||
tr("New release available."),
|
||||
tr("This is new version which can be\ndownloaded."));
|
||||
m_btnUpdate->setEnabled(true);
|
||||
m_btnUpdate->setToolTip(is_self_update_for_this_system ?
|
||||
tr("Download installation file for your OS.") :
|
||||
tr("Installation file is not available directly.\n"
|
||||
"Go to application website to obtain it manually."));
|
||||
|
||||
m_btnUpdate->setText(is_self_update_for_this_system ? tr("Download update") : tr("Go to application website"));
|
||||
if (self_update_supported) {
|
||||
loadAvailableFiles();
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_ui->m_lblStatus->setStatus(WidgetWithStatus::Warning,
|
||||
tr("No new release available."),
|
||||
tr("This release is not newer than\ncurrently installed one."));
|
||||
m_btnUpdate->setEnabled(false);
|
||||
m_btnUpdate->setToolTip(tr("No new update available."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FormUpdate::updateProgress(qint64 bytes_received, qint64 bytes_total) {
|
||||
if (bytes_received % 10 == 0) {
|
||||
qApp->processEvents();
|
||||
if (bytes_received - m_lastDownloadedBytes > 500000 || m_lastDownloadedBytes == 0) {
|
||||
m_ui->m_lblStatus->setStatus(WidgetWithStatus::Information,
|
||||
tr("Downloaded %1% (update size is %2 kB).").arg(QString::number(bytes_total == 0 ? 0 : (bytes_received * 100.0) / bytes_total,
|
||||
'f',
|
||||
@ -117,11 +118,14 @@ void FormUpdate::updateProgress(qint64 bytes_received, qint64 bytes_total) {
|
||||
'f',
|
||||
2)),
|
||||
tr("Downloading update..."));
|
||||
m_ui->m_lblStatus->repaint();
|
||||
|
||||
m_lastDownloadedBytes = bytes_received;
|
||||
}
|
||||
}
|
||||
|
||||
void FormUpdate::saveUpdateFile(const QByteArray &file_contents) {
|
||||
const QString url_file = m_updateInfo.m_urls.value(OS_ID).m_fileUrl;;
|
||||
const QString url_file = m_ui->m_listFiles->currentItem()->data(Qt::UserRole).toString();
|
||||
const QString temp_directory = qApp->getTempFolderPath();
|
||||
|
||||
if (!temp_directory.isEmpty()) {
|
||||
@ -151,13 +155,34 @@ void FormUpdate::saveUpdateFile(const QByteArray &file_contents) {
|
||||
}
|
||||
}
|
||||
|
||||
void FormUpdate::loadAvailableFiles() {
|
||||
m_ui->m_listFiles->clear();
|
||||
|
||||
foreach (const UpdateUrl &url, m_updateInfo.m_urls) {
|
||||
QListWidgetItem *item = new QListWidgetItem(url.m_name + tr(" (size ") + url.m_size + QSL(")"));
|
||||
item->setData(Qt::UserRole, url.m_fileUrl);
|
||||
item->setToolTip(url.m_fileUrl);
|
||||
m_ui->m_listFiles->addItem(item);
|
||||
}
|
||||
|
||||
if (m_ui->m_listFiles->count() > 0) {
|
||||
m_ui->m_listFiles->setCurrentRow(0);
|
||||
}
|
||||
else {
|
||||
m_btnUpdate->setEnabled(false);
|
||||
}
|
||||
|
||||
m_ui->m_tabInfo->addTab(m_ui->tabFiles, tr("Available update files"));
|
||||
m_ui->m_tabInfo->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void FormUpdate::updateCompleted(QNetworkReply::NetworkError status, QByteArray contents) {
|
||||
qDebug("Download of application update file was completed with code '%d'.", status);
|
||||
|
||||
switch (status) {
|
||||
case QNetworkReply::NoError:
|
||||
saveUpdateFile(contents);
|
||||
m_ui->m_lblStatus->setStatus(WidgetWithStatus::Ok, tr("Downloaded successfully"), tr("Package was downloaded successfully.\nYou must install it manually."));
|
||||
m_ui->m_lblStatus->setStatus(WidgetWithStatus::Ok, tr("Downloaded successfully"), tr("Package was downloaded successfully.\nYou can install it now."));
|
||||
m_btnUpdate->setText(tr("Install"));
|
||||
m_btnUpdate->setEnabled(true);
|
||||
break;
|
||||
@ -171,10 +196,11 @@ void FormUpdate::updateCompleted(QNetworkReply::NetworkError status, QByteArray
|
||||
|
||||
void FormUpdate::startUpdate() {
|
||||
QString url_file;
|
||||
const bool update_for_this_system = isUpdateForThisSystem() && isSelfUpdateSupported();
|
||||
const bool update_for_this_system = isSelfUpdateSupported();
|
||||
|
||||
if (update_for_this_system) {
|
||||
url_file = m_updateInfo.m_urls.value(OS_ID).m_fileUrl;
|
||||
if (update_for_this_system && m_ui->m_listFiles->currentItem() != nullptr) {
|
||||
url_file = m_ui->m_listFiles->currentItem()->data(Qt::UserRole).toString();
|
||||
m_ui->m_listFiles->setEnabled(false);
|
||||
}
|
||||
else {
|
||||
url_file = APP_URL;
|
||||
|
@ -38,15 +38,11 @@ class FormUpdate : public QDialog {
|
||||
explicit FormUpdate(QWidget *parent = 0);
|
||||
virtual ~FormUpdate();
|
||||
|
||||
// Returns true if current update provides
|
||||
// installation file for current platform.
|
||||
bool isUpdateForThisSystem() const;
|
||||
|
||||
// Returns true if application can self-update
|
||||
// on current platform.
|
||||
bool isSelfUpdateSupported() const;
|
||||
|
||||
protected slots:
|
||||
private slots:
|
||||
// Check for updates and interprets the results.
|
||||
void checkForUpdates();
|
||||
void startUpdate();
|
||||
@ -56,12 +52,15 @@ class FormUpdate : public QDialog {
|
||||
void saveUpdateFile(const QByteArray &file_contents);
|
||||
|
||||
private:
|
||||
void loadAvailableFiles();
|
||||
|
||||
Downloader *m_downloader;
|
||||
bool m_readyToInstall;
|
||||
QString m_updateFilePath;
|
||||
QScopedPointer<Ui::FormUpdate> m_ui;
|
||||
UpdateInfo m_updateInfo;
|
||||
QPushButton *m_btnUpdate;
|
||||
qint64 m_lastDownloadedBytes;
|
||||
};
|
||||
|
||||
#endif // FORMUPDATE_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>607</width>
|
||||
<height>366</height>
|
||||
<height>326</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -15,10 +15,7 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
@ -40,16 +37,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Changes</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>m_txtChanges</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="m_lblAvailableRelease">
|
||||
<property name="text">
|
||||
@ -75,37 +62,85 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QTextEdit" name="m_txtChanges">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
<widget class="QTabWidget" name="m_tabInfo">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>DejaVu Sans Mono</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="undoRedoEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QTextEdit::WidgetWidth</enum>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="html">
|
||||
<string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<widget class="QWidget" name="tabChanges">
|
||||
<attribute name="title">
|
||||
<string>Changelog</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="m_txtChanges">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>DejaVu Sans Mono</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="undoRedoEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QTextEdit::WidgetWidth</enum>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="html">
|
||||
<string notr="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:'DejaVu Sans Mono'; font-size:8.25pt; 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; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p></body></html></string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabFiles">
|
||||
<attribute name="title">
|
||||
<string>Available files</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="m_listFiles"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -28,9 +28,9 @@
|
||||
#include <QString>
|
||||
#include <QProcess>
|
||||
#include <QFile>
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
#include <QDomAttr>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QFuture>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
@ -205,18 +205,15 @@ QString SystemFactory::getUsername() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
QPair<UpdateInfo, QNetworkReply::NetworkError> SystemFactory::checkForUpdates() const {
|
||||
QPair<UpdateInfo, QNetworkReply::NetworkError> result;
|
||||
QByteArray releases_xml;
|
||||
QByteArray changelog;
|
||||
QPair<QList<UpdateInfo>, QNetworkReply::NetworkError> SystemFactory::checkForUpdates() const {
|
||||
QPair<QList<UpdateInfo>, QNetworkReply::NetworkError> result;
|
||||
QByteArray releases_json;
|
||||
|
||||
result.second = NetworkFactory::performNetworkOperation(RELEASES_LIST, DOWNLOAD_TIMEOUT, QByteArray(), QString(),
|
||||
releases_xml, QNetworkAccessManager::GetOperation).first;
|
||||
NetworkFactory::performNetworkOperation(CHANGELOG, DOWNLOAD_TIMEOUT, QByteArray(), QString(), changelog,
|
||||
QNetworkAccessManager::GetOperation);
|
||||
releases_json, QNetworkAccessManager::GetOperation).first;
|
||||
|
||||
if (result.second == QNetworkReply::NoError) {
|
||||
result.first = parseUpdatesFile(releases_xml, changelog);
|
||||
result.first = parseUpdatesFile(releases_json);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -267,43 +264,47 @@ bool SystemFactory::openFolderFile(const QString &file_path) {
|
||||
#endif
|
||||
}
|
||||
|
||||
UpdateInfo SystemFactory::parseUpdatesFile(const QByteArray &updates_file, const QByteArray &changelog) const {
|
||||
UpdateInfo update;
|
||||
QDomDocument document; document.setContent(updates_file, false);
|
||||
const QDomNodeList releases = document.elementsByTagName(QSL("release"));
|
||||
QList<UpdateInfo> SystemFactory::parseUpdatesFile(const QByteArray &updates_file) const {
|
||||
QList<UpdateInfo> updates;
|
||||
|
||||
if (releases.size() == 1) {
|
||||
QDomElement rel_elem = releases.at(0).toElement();
|
||||
QJsonArray document = QJsonDocument::fromJson(updates_file).array();
|
||||
|
||||
update.m_availableVersion = rel_elem.attributes().namedItem(QSL("version")).toAttr().value();
|
||||
update.m_changes = QString::fromUtf8(changelog);
|
||||
for (int i = 0; i < document.size(); i++) {
|
||||
QJsonObject release = document.at(i).toObject();
|
||||
UpdateInfo update;
|
||||
|
||||
QDomNodeList urls = rel_elem.elementsByTagName(QSL("url"));
|
||||
update.m_date = QDateTime::fromString(release["published_at"].toString(), QSL("yyyy-MM-ddTHH:mm:ssZ"));
|
||||
update.m_availableVersion = release["tag_name"].toString();
|
||||
update.m_changes = release["body"].toString();
|
||||
|
||||
for (int j = 0; j < urls.size(); j++) {
|
||||
QJsonArray assets = release["assets"].toArray();
|
||||
|
||||
for (int j = 0; j < assets.size(); j++) {
|
||||
QJsonObject asset = assets.at(j).toObject();
|
||||
UpdateUrl url;
|
||||
QDomElement url_elem = urls.at(j).toElement();
|
||||
|
||||
url.m_fileUrl = url_elem.text();
|
||||
url.m_os = url_elem.attributes().namedItem(QSL("os")).toAttr().value();
|
||||
url.m_platform = url_elem.attributes().namedItem(QSL("platform")).toAttr().value();
|
||||
url.m_fileUrl = asset["browser_download_url"].toString();
|
||||
url.m_name = asset["name"].toString();
|
||||
url.m_size = asset["size"].toVariant().toString() + tr(" bytes");
|
||||
|
||||
update.m_urls.insert(url.m_os, url);
|
||||
update.m_urls.append(url);
|
||||
}
|
||||
}
|
||||
else {
|
||||
update.m_availableVersion = QString();
|
||||
|
||||
updates.append(update);
|
||||
}
|
||||
|
||||
qSort(updates.begin(), updates.end(), [](const UpdateInfo &a, const UpdateInfo &b) -> bool {
|
||||
return a.m_date > b.m_date;
|
||||
});
|
||||
|
||||
return update;
|
||||
return updates;
|
||||
}
|
||||
|
||||
void SystemFactory::checkForUpdatesOnStartup() {
|
||||
const UpdateCheck updates = checkForUpdates();
|
||||
const QPair<QList<UpdateInfo>, QNetworkReply::NetworkError> updates = checkForUpdates();
|
||||
|
||||
if (updates.second == QNetworkReply::NoError && isVersionNewer(updates.first.m_availableVersion,
|
||||
APP_VERSION)) {
|
||||
if (!updates.first.isEmpty() && updates.second == QNetworkReply::NoError && isVersionNewer(updates.first.at(0).m_availableVersion,
|
||||
APP_VERSION)) {
|
||||
qApp->showGuiMessage(tr("New version available"),
|
||||
tr("Click the bubble for more information."),
|
||||
QSystemTrayIcon::Information,
|
||||
|
@ -29,18 +29,19 @@
|
||||
class UpdateUrl {
|
||||
public:
|
||||
QString m_fileUrl;
|
||||
QString m_platform;
|
||||
QString m_os;
|
||||
QString m_name;
|
||||
QString m_size;
|
||||
};
|
||||
|
||||
class UpdateInfo {
|
||||
public:
|
||||
explicit UpdateInfo() : m_availableVersion(QString()), m_changes(QString()) {
|
||||
explicit UpdateInfo() : m_availableVersion(QString()), m_changes(QString()), m_urls(QList<UpdateUrl>()) {
|
||||
}
|
||||
|
||||
QString m_availableVersion;
|
||||
QString m_changes;
|
||||
QHash<QString, UpdateUrl> m_urls;
|
||||
QList<UpdateUrl> m_urls;
|
||||
QDateTime m_date;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(UpdateInfo)
|
||||
@ -84,7 +85,7 @@ class SystemFactory : public QObject {
|
||||
QString getUsername() const;
|
||||
|
||||
// Tries to download list with new updates.
|
||||
QPair<UpdateInfo, QNetworkReply::NetworkError> checkForUpdates() const;
|
||||
QPair<QList<UpdateInfo>, QNetworkReply::NetworkError> checkForUpdates() const;
|
||||
|
||||
// Checks if update is newer than current application version.
|
||||
static bool isVersionNewer(const QString &new_version, const QString &base_version);
|
||||
@ -97,7 +98,7 @@ class SystemFactory : public QObject {
|
||||
|
||||
private:
|
||||
// Performs parsing of downloaded file with list of updates.
|
||||
UpdateInfo parseUpdatesFile(const QByteArray &updates_file, const QByteArray &changelog) const;
|
||||
QList<UpdateInfo> parseUpdatesFile(const QByteArray &updates_file) const;
|
||||
};
|
||||
|
||||
#endif // SYSTEMFACTORY_H
|
||||
|
@ -94,3 +94,7 @@ QStringList FeedParser::textsFromPath(const QDomElement &element, const QString
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString FeedParser::feedAuthor() const {
|
||||
return "";
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class FeedParser {
|
||||
protected:
|
||||
QStringList textsFromPath(const QDomElement &element, const QString &namespace_uri, const QString &xml_path, bool only_first) const;
|
||||
virtual QDomNodeList messageElements() = 0;
|
||||
virtual QString feedAuthor() const = 0;
|
||||
virtual QString feedAuthor() const;
|
||||
virtual Message extractMessage(const QDomElement &msg_element, QDateTime current_time) const = 0;
|
||||
|
||||
protected:
|
||||
|
@ -19,105 +19,104 @@
|
||||
|
||||
#include "miscellaneous/textfactory.h"
|
||||
#include "network-web/webfactory.h"
|
||||
#include "miscellaneous/iofactory.h"
|
||||
#include "exceptions/applicationexception.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
|
||||
|
||||
RssParser::RssParser() {
|
||||
RssParser::RssParser(const QString &data) : FeedParser(data) {
|
||||
}
|
||||
|
||||
RssParser::~RssParser() {
|
||||
}
|
||||
|
||||
QList<Message> RssParser::parseXmlData(const QString &data) {
|
||||
QList<Message> messages;
|
||||
QDomDocument xml_file;
|
||||
QDateTime current_time = QDateTime::currentDateTime();
|
||||
QDomNodeList RssParser::messageElements() {
|
||||
QDomNode channel_elem = m_xml.namedItem(QSL("rss")).namedItem(QSL("channel"));
|
||||
|
||||
xml_file.setContent(data, true);
|
||||
if (channel_elem.isNull()) {
|
||||
return QDomNodeList();
|
||||
}
|
||||
else {
|
||||
return channel_elem.toElement().elementsByTagName(QSL("item"));
|
||||
}
|
||||
}
|
||||
|
||||
// Pull out all messages.
|
||||
QDomNodeList messages_in_xml = xml_file.elementsByTagName(QSL("item"));
|
||||
Message RssParser::extractMessage(const QDomElement &msg_element, QDateTime current_time) const {
|
||||
Message new_message;
|
||||
|
||||
for (int i = 0; i < messages_in_xml.size(); i++) {
|
||||
QDomNode message_item = messages_in_xml.item(i);
|
||||
Message new_message;
|
||||
// Deal with titles & descriptions.
|
||||
QString elem_title = msg_element.namedItem(QSL("title")).toElement().text().simplified();
|
||||
QString elem_description = msg_element.namedItem(QSL("encoded")).toElement().text();
|
||||
QString elem_enclosure = msg_element.namedItem(QSL("enclosure")).toElement().attribute(QSL("url"));
|
||||
QString elem_enclosure_type = msg_element.namedItem(QSL("enclosure")).toElement().attribute(QSL("type"));
|
||||
|
||||
// Deal with titles & descriptions.
|
||||
QString elem_title = message_item.namedItem(QSL("title")).toElement().text().simplified();
|
||||
QString elem_description = message_item.namedItem(QSL("encoded")).toElement().text();
|
||||
QString elem_enclosure = message_item.namedItem(QSL("enclosure")).toElement().attribute(QSL("url"));
|
||||
QString elem_enclosure_type = message_item.namedItem(QSL("enclosure")).toElement().attribute(QSL("type"));
|
||||
|
||||
if (elem_description.isEmpty()) {
|
||||
elem_description = message_item.namedItem(QSL("description")).toElement().text();
|
||||
}
|
||||
|
||||
// Now we obtained maximum of information for title & description.
|
||||
if (elem_title.isEmpty()) {
|
||||
if (elem_description.isEmpty()) {
|
||||
// BOTH title and description are empty, skip this message.
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// Title is empty but description is not.
|
||||
new_message.m_title = WebFactory::instance()->stripTags(elem_description.simplified());
|
||||
new_message.m_contents = elem_description;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Title is really not empty, description does not matter.
|
||||
new_message.m_title = WebFactory::instance()->stripTags(elem_title);
|
||||
new_message.m_contents = elem_description;
|
||||
}
|
||||
|
||||
if (!elem_enclosure.isEmpty()) {
|
||||
new_message.m_enclosures.append(Enclosure(elem_enclosure, elem_enclosure_type));
|
||||
|
||||
qDebug("Adding enclosure '%s' for the message.", qPrintable(elem_enclosure));
|
||||
}
|
||||
|
||||
// Deal with link and author.
|
||||
new_message.m_url = message_item.namedItem(QSL("link")).toElement().text();
|
||||
|
||||
if (new_message.m_url.isEmpty() && !new_message.m_enclosures.isEmpty()) {
|
||||
new_message.m_url = new_message.m_enclosures.first().m_url;
|
||||
}
|
||||
|
||||
if (new_message.m_url.isEmpty()) {
|
||||
// Try to get "href" attribute.
|
||||
new_message.m_url = message_item.namedItem(QSL("link")).toElement().attribute(QSL("href"));
|
||||
}
|
||||
|
||||
new_message.m_author = message_item.namedItem(QSL("author")).toElement().text();
|
||||
|
||||
if (new_message.m_author.isEmpty()) {
|
||||
new_message.m_author = message_item.namedItem(QSL("creator")).toElement().text();
|
||||
}
|
||||
|
||||
// Deal with creation date.
|
||||
new_message.m_created = TextFactory::parseDateTime(message_item.namedItem(QSL("pubDate")).toElement().text());
|
||||
|
||||
if (new_message.m_created.isNull()) {
|
||||
new_message.m_created = TextFactory::parseDateTime(message_item.namedItem(QSL("date")).toElement().text());
|
||||
}
|
||||
|
||||
if (!(new_message.m_createdFromFeed = !new_message.m_created.isNull())) {
|
||||
// Date was NOT obtained from the feed,
|
||||
// set current date as creation date for the message.
|
||||
new_message.m_created = current_time;
|
||||
}
|
||||
|
||||
if (new_message.m_author.isNull()) {
|
||||
new_message.m_author = "";
|
||||
}
|
||||
|
||||
if (new_message.m_url.isNull()) {
|
||||
new_message.m_url = "";
|
||||
}
|
||||
|
||||
messages.append(new_message);
|
||||
if (elem_description.isEmpty()) {
|
||||
elem_description = msg_element.namedItem(QSL("description")).toElement().text();
|
||||
}
|
||||
|
||||
return messages;
|
||||
// Now we obtained maximum of information for title & description.
|
||||
if (elem_title.isEmpty()) {
|
||||
if (elem_description.isEmpty()) {
|
||||
// BOTH title and description are empty, skip this message.
|
||||
throw new ApplicationException(QSL("Not enough data for the message."));
|
||||
}
|
||||
else {
|
||||
// Title is empty but description is not.
|
||||
new_message.m_title = WebFactory::instance()->stripTags(elem_description.simplified());
|
||||
new_message.m_contents = elem_description;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Title is really not empty, description does not matter.
|
||||
new_message.m_title = WebFactory::instance()->stripTags(elem_title);
|
||||
new_message.m_contents = elem_description;
|
||||
}
|
||||
|
||||
if (!elem_enclosure.isEmpty()) {
|
||||
new_message.m_enclosures.append(Enclosure(elem_enclosure, elem_enclosure_type));
|
||||
|
||||
qDebug("Adding enclosure '%s' for the message.", qPrintable(elem_enclosure));
|
||||
}
|
||||
|
||||
// Deal with link and author.
|
||||
new_message.m_url = msg_element.namedItem(QSL("link")).toElement().text();
|
||||
|
||||
if (new_message.m_url.isEmpty() && !new_message.m_enclosures.isEmpty()) {
|
||||
new_message.m_url = new_message.m_enclosures.first().m_url;
|
||||
}
|
||||
|
||||
if (new_message.m_url.isEmpty()) {
|
||||
// Try to get "href" attribute.
|
||||
new_message.m_url = msg_element.namedItem(QSL("link")).toElement().attribute(QSL("href"));
|
||||
}
|
||||
|
||||
new_message.m_author = msg_element.namedItem(QSL("author")).toElement().text();
|
||||
|
||||
if (new_message.m_author.isEmpty()) {
|
||||
new_message.m_author = msg_element.namedItem(QSL("creator")).toElement().text();
|
||||
}
|
||||
|
||||
// Deal with creation date.
|
||||
new_message.m_created = TextFactory::parseDateTime(msg_element.namedItem(QSL("pubDate")).toElement().text());
|
||||
|
||||
if (new_message.m_created.isNull()) {
|
||||
new_message.m_created = TextFactory::parseDateTime(msg_element.namedItem(QSL("date")).toElement().text());
|
||||
}
|
||||
|
||||
if (!(new_message.m_createdFromFeed = !new_message.m_created.isNull())) {
|
||||
// Date was NOT obtained from the feed,
|
||||
// set current date as creation date for the message.
|
||||
new_message.m_created = current_time;
|
||||
}
|
||||
|
||||
if (new_message.m_author.isNull()) {
|
||||
new_message.m_author = "";
|
||||
}
|
||||
|
||||
if (new_message.m_url.isNull()) {
|
||||
new_message.m_url = "";
|
||||
}
|
||||
|
||||
return new_message;
|
||||
}
|
||||
|
@ -18,17 +18,21 @@
|
||||
#ifndef RSSPARSER_H
|
||||
#define RSSPARSER_H
|
||||
|
||||
#include "services/standard/feedparser.h"
|
||||
|
||||
#include "core/message.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
|
||||
class RssParser {
|
||||
class RssParser : public FeedParser {
|
||||
public:
|
||||
explicit RssParser();
|
||||
explicit RssParser(const QString &data);
|
||||
virtual ~RssParser();
|
||||
|
||||
QList<Message> parseXmlData(const QString &data);
|
||||
private:
|
||||
QDomNodeList messageElements();
|
||||
Message extractMessage(const QDomElement &msg_element, QDateTime current_time) const;
|
||||
};
|
||||
|
||||
#endif // RSSPARSER_H
|
||||
|
@ -446,7 +446,7 @@ QList<Message> StandardFeed::obtainNewMessages(bool *error_during_obtaining) {
|
||||
switch (type()) {
|
||||
case StandardFeed::Rss0X:
|
||||
case StandardFeed::Rss2X:
|
||||
messages = RssParser().parseXmlData(formatted_feed_contents);
|
||||
messages = RssParser(formatted_feed_contents).messages();
|
||||
break;
|
||||
|
||||
case StandardFeed::Rdf:
|
||||
|
Loading…
x
Reference in New Issue
Block a user