diff options
Diffstat (limited to 'examples/network/rsslisting')
-rw-r--r-- | examples/network/rsslisting/CMakeLists.txt | 39 | ||||
-rw-r--r-- | examples/network/rsslisting/main.cpp | 16 | ||||
-rw-r--r-- | examples/network/rsslisting/rsslisting.cpp | 126 | ||||
-rw-r--r-- | examples/network/rsslisting/rsslisting.h | 54 | ||||
-rw-r--r-- | examples/network/rsslisting/rsslisting.pro | 8 |
5 files changed, 243 insertions, 0 deletions
diff --git a/examples/network/rsslisting/CMakeLists.txt b/examples/network/rsslisting/CMakeLists.txt new file mode 100644 index 0000000000..58d9edcb92 --- /dev/null +++ b/examples/network/rsslisting/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(rsslisting LANGUAGES CXX) + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Network Widgets) + +qt_standard_project_setup() + +qt_add_executable(rsslisting + main.cpp + rsslisting.cpp rsslisting.h +) + +set_target_properties(rsslisting PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(rsslisting PRIVATE + Qt6::Core + Qt6::Gui + Qt6::Network + Qt6::Widgets +) + +install(TARGETS rsslisting + BUNDLE DESTINATION . + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +qt_generate_deploy_app_script( + TARGET rsslisting + OUTPUT_SCRIPT deploy_script + NO_UNSUPPORTED_PLATFORM_ERROR +) +install(SCRIPT ${deploy_script}) diff --git a/examples/network/rsslisting/main.cpp b/examples/network/rsslisting/main.cpp new file mode 100644 index 0000000000..7a64db8a0c --- /dev/null +++ b/examples/network/rsslisting/main.cpp @@ -0,0 +1,16 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "rsslisting.h" +#include <QtWidgets> +using namespace Qt::StringLiterals; + +//! [0] +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + RSSListing rsslisting(u"https://www.qt.io/blog/rss.xml"_s); + rsslisting.show(); + return app.exec(); +} +//! [0] diff --git a/examples/network/rsslisting/rsslisting.cpp b/examples/network/rsslisting/rsslisting.cpp new file mode 100644 index 0000000000..ed7c163c76 --- /dev/null +++ b/examples/network/rsslisting/rsslisting.cpp @@ -0,0 +1,126 @@ +// 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] diff --git a/examples/network/rsslisting/rsslisting.h b/examples/network/rsslisting/rsslisting.h new file mode 100644 index 0000000000..499bc5d1d4 --- /dev/null +++ b/examples/network/rsslisting/rsslisting.h @@ -0,0 +1,54 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef RSSLISTING_H +#define RSSLISTING_H + +#include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QWidget> +#include <QXmlStreamReader> + +QT_BEGIN_NAMESPACE +class QLineEdit; +class QPushButton; +class QTreeWidget; +class QTreeWidgetItem; +class QUrl; +QT_END_NAMESPACE + +//! [0] +class RSSListing : public QWidget +{ + Q_OBJECT +public: + explicit RSSListing(const QString &url = QString(), QWidget *widget = nullptr); + +public slots: + void fetch(); + void finished(QNetworkReply *reply); + void consumeData(); + void error(QNetworkReply::NetworkError); + +private: + void parseXml(); + void get(const QUrl &url); + + // Parser state: + QXmlStreamReader xml; + QString currentTag; + QString linkString; + QString titleString; + + // Network state: + QNetworkAccessManager manager; + QNetworkReply *currentReply; + + // UI elements: + QLineEdit *lineEdit; + QTreeWidget *treeWidget; + QPushButton *fetchButton; +}; +//! [0] + +#endif diff --git a/examples/network/rsslisting/rsslisting.pro b/examples/network/rsslisting/rsslisting.pro new file mode 100644 index 0000000000..aacbe3127f --- /dev/null +++ b/examples/network/rsslisting/rsslisting.pro @@ -0,0 +1,8 @@ +HEADERS += rsslisting.h +SOURCES += main.cpp rsslisting.cpp +QT += network widgets +requires(qtConfig(treewidget)) + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/network/rsslisting +INSTALLS += target |