e54a7c5667
It's really showing how to request a resource and act on its becoming available. The use of XML to do so is incidental; the use of networking is central. Pick-to: 6.6 6.5 Task-number: QTBUG-111228 Change-Id: Ibcf438c7ef3b2464ddfa8b96a79fb15523e4a468 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
127 lines
3.8 KiB
C++
127 lines
3.8 KiB
C++
// Copyright (C) 2016 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
|
|
#include "rsslisting.h"
|
|
|
|
#include <QtCore>
|
|
#include <QtWidgets>
|
|
#include <QtNetwork>
|
|
|
|
//! [setup]
|
|
RSSListing::RSSListing(const QString &url, QWidget *parent)
|
|
: QWidget(parent), currentReply(0)
|
|
{
|
|
connect(&manager, &QNetworkAccessManager::finished, this, &RSSListing::finished);
|
|
|
|
lineEdit = new QLineEdit(this);
|
|
lineEdit->setText(url);
|
|
connect(lineEdit, &QLineEdit::returnPressed, this, &RSSListing::fetch);
|
|
|
|
fetchButton = new QPushButton(tr("Fetch"), this);
|
|
connect(fetchButton, &QPushButton::clicked, this, &RSSListing::fetch);
|
|
|
|
treeWidget = new QTreeWidget(this);
|
|
connect(treeWidget, &QTreeWidget::itemActivated,
|
|
// Open the link in the browser:
|
|
this, [](QTreeWidgetItem *item) { QDesktopServices::openUrl(QUrl(item->text(1))); });
|
|
treeWidget->setHeaderLabels(QStringList { tr("Title"), tr("Link") });
|
|
treeWidget->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
|
|
|
QHBoxLayout *hboxLayout = new QHBoxLayout;
|
|
hboxLayout->addWidget(lineEdit);
|
|
hboxLayout->addWidget(fetchButton);
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
|
layout->addLayout(hboxLayout);
|
|
layout->addWidget(treeWidget);
|
|
|
|
setWindowTitle(tr("RSS listing example"));
|
|
resize(640, 480);
|
|
}
|
|
//! [setup]
|
|
|
|
//! [slots]
|
|
void RSSListing::fetch()
|
|
{
|
|
lineEdit->setReadOnly(true);
|
|
fetchButton->setEnabled(false);
|
|
treeWidget->clear();
|
|
|
|
get(QUrl(lineEdit->text()));
|
|
}
|
|
|
|
void RSSListing::consumeData()
|
|
{
|
|
int statusCode = currentReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
|
if (statusCode >= 200 && statusCode < 300)
|
|
parseXml();
|
|
}
|
|
|
|
void RSSListing::error(QNetworkReply::NetworkError)
|
|
{
|
|
qWarning("error retrieving RSS feed");
|
|
xml.clear();
|
|
currentReply->disconnect(this);
|
|
currentReply->deleteLater();
|
|
currentReply = nullptr;
|
|
}
|
|
|
|
void RSSListing::finished(QNetworkReply *reply)
|
|
{
|
|
Q_UNUSED(reply);
|
|
lineEdit->setReadOnly(false);
|
|
fetchButton->setEnabled(true);
|
|
}
|
|
//! [slots]
|
|
|
|
// Private methods
|
|
|
|
//! [get]
|
|
void RSSListing::get(const QUrl &url)
|
|
{
|
|
if (currentReply) {
|
|
currentReply->disconnect(this);
|
|
currentReply->deleteLater();
|
|
}
|
|
currentReply = url.isValid() ? manager.get(QNetworkRequest(url)) : nullptr;
|
|
if (currentReply) {
|
|
connect(currentReply, &QNetworkReply::readyRead, this, &RSSListing::consumeData);
|
|
connect(currentReply, &QNetworkReply::errorOccurred, this, &RSSListing::error);
|
|
|
|
}
|
|
xml.setDevice(currentReply); // Equivalent to clear() if currentReply is null.
|
|
}
|
|
//! [get]
|
|
|
|
// TODO: this is a candidate for showing how to use coroutines, once available.
|
|
//! [parse]
|
|
void RSSListing::parseXml()
|
|
{
|
|
while (!xml.atEnd()) {
|
|
xml.readNext();
|
|
if (xml.isStartElement()) {
|
|
if (xml.name() == u"item") {
|
|
linkString = xml.attributes().value("rss:about").toString();
|
|
titleString.clear();
|
|
}
|
|
currentTag = xml.name().toString();
|
|
} else if (xml.isEndElement()) {
|
|
if (xml.name() == u"item") {
|
|
|
|
QTreeWidgetItem *item = new QTreeWidgetItem;
|
|
item->setText(0, titleString);
|
|
item->setText(1, linkString);
|
|
treeWidget->addTopLevelItem(item);
|
|
}
|
|
} else if (xml.isCharacters() && !xml.isWhitespace()) {
|
|
if (currentTag == "title")
|
|
titleString += xml.text();
|
|
else if (currentTag == "link")
|
|
linkString += xml.text();
|
|
}
|
|
}
|
|
if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError)
|
|
qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString();
|
|
}
|
|
//! [parse]
|