Advanced implementation of auto-fetch-guess feature.
This commit is contained in:
parent
36555ee943
commit
fb90fc91da
|
@ -5,17 +5,6 @@
|
|||
#include <QPointer>
|
||||
#include <QSqlDatabase>
|
||||
|
||||
// TODO: přidat podporu pro mysql
|
||||
// nemužu mit stejny SQL kod pro mysql a sqlite
|
||||
// ale musim docilit aby oba kody SQL delaly tabulky
|
||||
// se stejnymi atributy - stejnymi nazvy sloupcu
|
||||
// PROBLEMY se mysql: nutno pridat AUTO_INCREMENT u int primary keyů
|
||||
// taky bacha na nazvy sloupců, třeba
|
||||
// key a read sou klicovy slouva a fejlne to tak
|
||||
// taky bacha ze typ TEXT nemuze bejt dost dobre
|
||||
// pouzitej v UNIQUE CHECK, misto toho se da pouzit treba
|
||||
// VARCHAR (100)
|
||||
|
||||
|
||||
class DatabaseFactory : public QObject {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
#include <QTextCodec>
|
||||
#include <QSqlQuery>
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QDomNode>
|
||||
#include <QDomElement>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
|
||||
FeedsModelStandardFeed::FeedsModelStandardFeed(FeedsModelRootItem *parent_item)
|
||||
: FeedsModelFeed(parent_item),
|
||||
|
@ -44,15 +49,117 @@ FeedsModelStandardFeed *FeedsModelStandardFeed::loadFromRecord(const QSqlRecord
|
|||
return feed;
|
||||
}
|
||||
|
||||
FeedsModelStandardFeed *FeedsModelStandardFeed::guessFeed(const QString &url,
|
||||
const QString &username,
|
||||
const QString &password) {
|
||||
// TODO: http://www.google.com/s2/favicons?domain=root.cz
|
||||
// ZISKAT ikonu (napsat taky aby se dala ikona pro
|
||||
// dane url ziskavat taky samostatne
|
||||
// pak ziskat informace o kanalu
|
||||
QPair<FeedsModelStandardFeed*, QNetworkReply::NetworkError> FeedsModelStandardFeed::guessFeed(const QString &url,
|
||||
const QString &username,
|
||||
const QString &password) {
|
||||
QPair<FeedsModelStandardFeed*, QNetworkReply::NetworkError> result; result.first = NULL;
|
||||
|
||||
return NULL;
|
||||
// Try to obtain icon.
|
||||
QIcon icon_data;
|
||||
|
||||
if (NetworkFactory::downloadIcon(url,
|
||||
5000,
|
||||
icon_data) == QNetworkReply::NoError) {
|
||||
// Icon for feed was downloaded and is stored now in _icon_data.
|
||||
result.first = new FeedsModelStandardFeed();
|
||||
result.first->setIcon(icon_data);
|
||||
}
|
||||
|
||||
QByteArray feed_contents;
|
||||
if ((result.second = NetworkFactory::downloadFeedFile(url,
|
||||
Settings::instance()->value(APP_CFG_FEEDS, "feed_update_timeout", DOWNLOAD_TIMEOUT).toInt(),
|
||||
feed_contents,
|
||||
true,
|
||||
username,
|
||||
password)) == QNetworkReply::NoError) {
|
||||
// Feed XML was obtained, now we need to try to guess
|
||||
// its encoding before we can read further data.
|
||||
|
||||
QXmlStreamReader xml_stream_reader(feed_contents);
|
||||
QString xml_schema_encoding;
|
||||
QString xml_contents_encoded;
|
||||
|
||||
// We have several chances to read the XML version directly
|
||||
// from XML declaration.
|
||||
for (int i = 0; i < 2 && !xml_stream_reader.atEnd(); i++) {
|
||||
if ((xml_schema_encoding = xml_stream_reader.documentEncoding().toString()).isEmpty()) {
|
||||
xml_stream_reader.readNext();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QTextCodec *custom_codec = QTextCodec::codecForName(xml_schema_encoding.toLocal8Bit());
|
||||
|
||||
if (custom_codec != NULL) {
|
||||
// Feed encoding was probably guessed.
|
||||
xml_contents_encoded = custom_codec->toUnicode(feed_contents);
|
||||
result.first->setEncoding(xml_schema_encoding);
|
||||
}
|
||||
else {
|
||||
// Feed encoding probably not guessed, set it as
|
||||
// default.
|
||||
xml_contents_encoded = feed_contents;
|
||||
result.first->setEncoding(DEFAULT_FEED_ENCODING);
|
||||
}
|
||||
|
||||
// Feed XML was obtained, guess it now.
|
||||
QDomDocument xml_document;
|
||||
|
||||
if (!xml_document.setContent(xml_contents_encoded)) {
|
||||
// XML is invalid, exit.
|
||||
return result;
|
||||
}
|
||||
|
||||
QDomElement root_element = xml_document.documentElement();
|
||||
QString root_tag_name = root_element.tagName();
|
||||
|
||||
if (root_tag_name == "rdf:RDF") {
|
||||
if (result.first == NULL) {
|
||||
result.first = new FeedsModelStandardFeed();
|
||||
}
|
||||
|
||||
// We found RDF feed.
|
||||
QDomElement channel_element = root_element.namedItem("channel").toElement();
|
||||
|
||||
result.first->setType(StandardRdf);
|
||||
result.first->setTitle(channel_element.namedItem("title").toElement().text());
|
||||
result.first->setDescription(channel_element.namedItem("description").toElement().text());
|
||||
}
|
||||
else if (root_tag_name == "rss") {
|
||||
if (result.first == NULL) {
|
||||
result.first = new FeedsModelStandardFeed();
|
||||
}
|
||||
|
||||
// We found RSS 0.91/0.92/0.93/2.0/2.0.1 feed.
|
||||
QString rss_type = root_element.attribute("version", "2.0");
|
||||
|
||||
if (rss_type == "0.91" || rss_type == "0.92" || rss_type == "0.93") {
|
||||
result.first->setType(StandardRss0X);
|
||||
}
|
||||
else {
|
||||
result.first->setType(StandardRss2X);
|
||||
}
|
||||
|
||||
QDomElement channel_element = root_element.namedItem("channel").toElement();
|
||||
|
||||
result.first->setTitle(channel_element.namedItem("title").toElement().text());
|
||||
result.first->setDescription(channel_element.namedItem("description").toElement().text());
|
||||
}
|
||||
else if (root_tag_name == "feed") {
|
||||
if (result.first == NULL) {
|
||||
result.first = new FeedsModelStandardFeed();
|
||||
}
|
||||
|
||||
// We found ATOM feed.
|
||||
result.first->setType(StandardAtom10);
|
||||
result.first->setTitle(root_element.namedItem("title").toElement().text());
|
||||
result.first->setDescription(root_element.namedItem("subtitle").toElement().text());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariant FeedsModelStandardFeed::data(int column, int role) const {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include <QDateTime>
|
||||
#include <QSqlRecord>
|
||||
#include <QPair>
|
||||
#include <QNetworkReply>
|
||||
|
||||
|
||||
class Message;
|
||||
|
@ -83,10 +85,12 @@ class FeedsModelStandardFeed : public FeedsModelFeed {
|
|||
|
||||
// Tries to guess feed hidden under given URL
|
||||
// and uses given credentials.
|
||||
// Returns NULL if something failed.
|
||||
static FeedsModelStandardFeed *guessFeed(const QString &url,
|
||||
const QString &username,
|
||||
const QString &password);
|
||||
// Returns pointer to guessed feed (if at least partially
|
||||
// guessed) and retrieved error/status code from network layer
|
||||
// or NULL feed.
|
||||
static QPair<FeedsModelStandardFeed*, QNetworkReply::NetworkError> guessFeed(const QString &url,
|
||||
const QString &username,
|
||||
const QString &password);
|
||||
|
||||
protected:
|
||||
// Persistently stores given messages into the database
|
||||
|
|
|
@ -5,11 +5,31 @@
|
|||
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
#include <QTextDocument>
|
||||
|
||||
|
||||
NetworkFactory::NetworkFactory() {
|
||||
}
|
||||
|
||||
QNetworkReply::NetworkError NetworkFactory::downloadIcon(const QString &url,
|
||||
int timeout,
|
||||
QIcon &output) {
|
||||
QString google_s2_with_url = QString("http://www.google.com/s2/favicons?domain=%1").arg(Qt::escape(url));
|
||||
QByteArray icon_data;
|
||||
|
||||
QNetworkReply::NetworkError network_result = downloadFeedFile(google_s2_with_url,
|
||||
timeout,
|
||||
icon_data);
|
||||
|
||||
if (network_result == QNetworkReply::NoError) {
|
||||
QPixmap icon_pixmap;
|
||||
icon_pixmap.loadFromData(icon_data);
|
||||
output = QIcon(icon_pixmap);
|
||||
}
|
||||
|
||||
return network_result;
|
||||
}
|
||||
|
||||
QNetworkReply::NetworkError NetworkFactory::downloadFeedFile(const QString &url,
|
||||
int timeout,
|
||||
QByteArray &output,
|
||||
|
|
|
@ -12,6 +12,12 @@ class NetworkFactory {
|
|||
explicit NetworkFactory();
|
||||
|
||||
public:
|
||||
// Performs SYNCHRONOUS download if favicon for the site,
|
||||
// given URL belongs to.
|
||||
static QNetworkReply::NetworkError downloadIcon(const QString &url,
|
||||
int timeout,
|
||||
QIcon &output);
|
||||
|
||||
// Performs SYNCHRONOUS download of file with given URL
|
||||
// and given timeout.
|
||||
static QNetworkReply::NetworkError downloadFeedFile(const QString &url,
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <QTextCodec>
|
||||
#include <QFileDialog>
|
||||
#include <QMenu>
|
||||
#include <QPair>
|
||||
#include <QNetworkReply>
|
||||
|
||||
|
||||
FormStandardFeedDetails::FormStandardFeedDetails(FeedsModel *model, QWidget *parent)
|
||||
|
@ -240,6 +242,25 @@ void FormStandardFeedDetails::apply() {
|
|||
}
|
||||
}
|
||||
|
||||
void FormStandardFeedDetails::guessFeed() {
|
||||
QPair<FeedsModelStandardFeed*, QNetworkReply::NetworkError> result = FeedsModelStandardFeed::guessFeed(m_ui->m_txtUrl->lineEdit()->text(),
|
||||
m_ui->m_txtUsername->lineEdit()->text(),
|
||||
m_ui->m_txtPassword->lineEdit()->text());
|
||||
|
||||
if (result.first != NULL) {
|
||||
// Icon was perhaps guessed.
|
||||
m_ui->m_btnIcon->setIcon(result.first->icon());
|
||||
|
||||
m_ui->m_txtTitle->lineEdit()->setText(result.first->title());
|
||||
m_ui->m_txtDescription->lineEdit()->setText(result.first->description());
|
||||
m_ui->m_cmbType->setCurrentIndex(m_ui->m_cmbType->findData(QVariant::fromValue((int) result.first->type())));
|
||||
m_ui->m_cmbEncoding->setCurrentIndex(m_ui->m_cmbEncoding->findData(result.first->encoding(), Qt::DisplayRole));
|
||||
}
|
||||
else {
|
||||
// No feed guessed, even no icon available.
|
||||
}
|
||||
}
|
||||
|
||||
void FormStandardFeedDetails::createConnections() {
|
||||
// General connections.
|
||||
connect(m_ui->m_buttonBox, SIGNAL(accepted()),
|
||||
|
@ -258,6 +279,8 @@ void FormStandardFeedDetails::createConnections() {
|
|||
this, SLOT(onAuthenticationSwitched()));
|
||||
connect(m_ui->m_cmbAutoUpdateType, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(onAutoUpdateTypeChanged(int)));
|
||||
connect(m_btnLoadDataFromInternet, SIGNAL(clicked()),
|
||||
this, SLOT(guessFeed()));
|
||||
|
||||
// Icon connections.
|
||||
connect(m_actionLoadIconFromFile, SIGNAL(triggered()), this, SLOT(onLoadIconFromFile()));
|
||||
|
|
|
@ -30,6 +30,7 @@ class FormStandardFeedDetails : public QDialog {
|
|||
protected slots:
|
||||
// Applies changes.
|
||||
void apply();
|
||||
void guessFeed();
|
||||
|
||||
// Trigerred when title/description/url/username/password changes.
|
||||
void onTitleChanged(const QString &new_title);
|
||||
|
|
Loading…
Reference in New Issue