diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2023-06-07 15:32:28 +0200 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2023-06-14 11:57:31 +0200 |
commit | e54a7c56677280d9a9eb976dd455085dcce10c40 (patch) | |
tree | 63ac9abc55e98edf9f8ea9c6bc674b57f965cb54 /examples/corelib/serialization | |
parent | 4b6986db32eef511718e9010636c5485b6512ac9 (diff) |
Move RSS listing example to networking
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>
Diffstat (limited to 'examples/corelib/serialization')
-rw-r--r-- | examples/corelib/serialization/CMakeLists.txt | 3 | ||||
-rw-r--r-- | examples/corelib/serialization/rsslisting/CMakeLists.txt | 38 | ||||
-rw-r--r-- | examples/corelib/serialization/rsslisting/doc/images/rsslisting.png | bin | 19739 -> 0 bytes | |||
-rw-r--r-- | examples/corelib/serialization/rsslisting/doc/src/rsslisting.qdoc | 129 | ||||
-rw-r--r-- | examples/corelib/serialization/rsslisting/main.cpp | 16 | ||||
-rw-r--r-- | examples/corelib/serialization/rsslisting/rsslisting.cpp | 126 | ||||
-rw-r--r-- | examples/corelib/serialization/rsslisting/rsslisting.h | 54 | ||||
-rw-r--r-- | examples/corelib/serialization/rsslisting/rsslisting.pro | 8 | ||||
-rw-r--r-- | examples/corelib/serialization/serialization.pro | 2 |
9 files changed, 0 insertions, 376 deletions
diff --git a/examples/corelib/serialization/CMakeLists.txt b/examples/corelib/serialization/CMakeLists.txt index 7dd5d476d1..ad14a179b1 100644 --- a/examples/corelib/serialization/CMakeLists.txt +++ b/examples/corelib/serialization/CMakeLists.txt @@ -4,9 +4,6 @@ qt_internal_add_example(cbordump) qt_internal_add_example(convert) qt_internal_add_example(savegame) -if(TARGET Qt6::Network AND TARGET Qt6::Widgets) - qt_internal_add_example(rsslisting) -endif() if(TARGET Qt6::Widgets) qt_internal_add_example(streambookmarks) endif() diff --git a/examples/corelib/serialization/rsslisting/CMakeLists.txt b/examples/corelib/serialization/rsslisting/CMakeLists.txt deleted file mode 100644 index 405a01ce56..0000000000 --- a/examples/corelib/serialization/rsslisting/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause - -cmake_minimum_required(VERSION 3.16) -project(rsslisting LANGUAGES CXX) - -if(NOT DEFINED INSTALL_EXAMPLESDIR) - set(INSTALL_EXAMPLESDIR "examples") -endif() - -set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/serialization/rsslisting") - -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 - RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" - BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" - LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" -) diff --git a/examples/corelib/serialization/rsslisting/doc/images/rsslisting.png b/examples/corelib/serialization/rsslisting/doc/images/rsslisting.png Binary files differdeleted file mode 100644 index 0b05375f93..0000000000 --- a/examples/corelib/serialization/rsslisting/doc/images/rsslisting.png +++ /dev/null diff --git a/examples/corelib/serialization/rsslisting/doc/src/rsslisting.qdoc b/examples/corelib/serialization/rsslisting/doc/src/rsslisting.qdoc deleted file mode 100644 index 260d26811c..0000000000 --- a/examples/corelib/serialization/rsslisting/doc/src/rsslisting.qdoc +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -/*! - \example serialization/rsslisting - \examplecategory {Networking} - \meta tag {serialization} - \title A minimal RSS listing application - - \brief A demonstration of how to fetch and display a network resource. - - This example shows how to fetch a resource the user has requested and - display data contained in the response, illustrated by an RSS listing - application. (RDF Site Summary, or Really Simple Syndication, is a standard - format for communicating updates to web sites. See - https://www.rssboard.org/rss-specification for details.) The user inferface - in the illustration is simple, as the focus of this example is on how to use - networking, but naturally a more sophisticated interface would be wanted for - a serious RSS reader. - - The example also illustrates how to do asynchronous parsing of data as it is - received, preserving state in member variables so that an incremental parser - can consume chunks of data as they arrive over the network. Constituents of - the parsed content may start in one chunk of data but not be completed until - a later chunk, requiring the parser to retain state between calls. - - \image rsslisting.png - - The main program is fairly minimal. It simply instantiates a \l QApplication - and the \c RSSListing widget, shows the latter and hands over control to the - former. For the sake of illustration, it gives the widget the Qt blog's URL - as default value for the resource to check. - - \snippet serialization/rsslisting/main.cpp 0 - - \section1 The RSSListing class - - \snippet serialization/rsslisting/rsslisting.h 0 - - The widget itself provides a simple user interface for specifying the URL to - fetch and, once available updates are displayed, controlling the downloading - of updated items. A \l QLineEdit provides for input of the URL, and a - \l QTreeWidget for display of the results once fetched. - - The widget downloads and parses the RSS (a form of XML) asynchronously, - feeding the data to an XML reader as it arrives. This supports reading of - very large data sources. Because the data is streamed from the network - through the XML reader, there is no need to retain the full text of the XML - in memory. In other context, a similar approach can allow the user to - interrupt such incremental loading. - - \section2 Construction - - \snippet serialization/rsslisting/rsslisting.cpp setup - - The constructor sets up the assorted components of the widget and connects - their various signals to the slots it shall use to handle them. - - The user interface consists of a line edit, a push button, and a list view - widget. The line edit is used for entering the URL to fetch; the push button - starts the process of fetching updates. The line edit is empty by default, - but the constructor's caller can override that, as our \c main() has done. - In any case, the user can replace the default with the URL of another RSS - feed. - - The list view shows the updated items reported in the RSS feed. - Double-clicking on one of these sends its URL to the user's browser or other - user agent using \l QDesktopServices::openUrl(). - - \section2 The slots - - \snippet serialization/rsslisting/rsslisting.cpp slots - - All slots are kept simple by delegating any hard work to private methods. - - When the user completes input of a URL, either by clicking the "Fetch" - button or by pressing the return key in the line edit, the \c fetch() slot - disables the "Fetch" button and disables further editing of the line edit. - It clears the display of available updates and delegates to \c get() the - initiating of an HTTP GET request. - - When data is received, the network reply triggers its \l {QNetworkReply::} - {readyRead()} signal, which \c get() connects to the \c consumeData() - slot. This checks the response got a successful status code and, if it did, - calls \c parseXml() to consume the data. - - If the network reply gets an error, this is delivered to the \c error() - slot, which reports the error, clears the XML stream reader then disconnects - from the reply and deletes it. - - On completion (whether successful or otherwise) of a network reply, the \c - finished() slot restores the UI to be ready to accept a new URL to fetch by - re-enabling the line edit and "Fetch" button. - - \section2 The get() method - - \snippet serialization/rsslisting/rsslisting.cpp get - - The private \c get() method is used by the \c fetch() slot to initiate an - HTTP GET request. It first clears the XML stream reader and, if a reply is - currently active, disconnects and deletes it. If the URL it has been passed - is valid, it asks the network access manager to GET it. It connects its - relevant slots to signals of the resulting reply (if any) and sets up its - XML stream reader to read data from the reply - a network reply object is - also a \c QIODevice, from which data can be read. - - \section2 The parseXml() method - - \snippet serialization/rsslisting/rsslisting.cpp parse - - When data is received, and thus made available to the XML stream reader, \c - parseXml() reads from the XML stream, checking for \c item elements and, - within them, \c title and \c link elements. It will use the \c{rss:about} - attribute of an \c item as URL in the Link column of the tree-view, failing - that the content of its \c link element; and it uses the content of the \c - title element in the Title column of the tree-view. As each \c item element - closes, its details are turned into a new row in the tree widget, with the - extracted title and URL in the Title and Link columns. - - The variables that keep track of the parsing state - \c linkString, \c - titleString and \c currentTag - are member variables of the \c RSSListing - class, even though they are only accessed from this method, because this - method may be called repeatedly, as new data arrives, and one chunk of - received data may start an element that isn't completed until a later chunk - arrives. This enables the parser to operate asynchronously as the data - arrives, instead of having to wait until all the data has arrived. - - \sa QNetworkReply, QXmlStreamReader -*/ diff --git a/examples/corelib/serialization/rsslisting/main.cpp b/examples/corelib/serialization/rsslisting/main.cpp deleted file mode 100644 index 7a64db8a0c..0000000000 --- a/examples/corelib/serialization/rsslisting/main.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// 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/corelib/serialization/rsslisting/rsslisting.cpp b/examples/corelib/serialization/rsslisting/rsslisting.cpp deleted file mode 100644 index ed7c163c76..0000000000 --- a/examples/corelib/serialization/rsslisting/rsslisting.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// 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/corelib/serialization/rsslisting/rsslisting.h b/examples/corelib/serialization/rsslisting/rsslisting.h deleted file mode 100644 index 499bc5d1d4..0000000000 --- a/examples/corelib/serialization/rsslisting/rsslisting.h +++ /dev/null @@ -1,54 +0,0 @@ -// 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/corelib/serialization/rsslisting/rsslisting.pro b/examples/corelib/serialization/rsslisting/rsslisting.pro deleted file mode 100644 index 7619755b8f..0000000000 --- a/examples/corelib/serialization/rsslisting/rsslisting.pro +++ /dev/null @@ -1,8 +0,0 @@ -HEADERS += rsslisting.h -SOURCES += main.cpp rsslisting.cpp -QT += network widgets -requires(qtConfig(treewidget)) - -# install -target.path = $$[QT_INSTALL_EXAMPLES]/corelib/serialization/rsslisting -INSTALLS += target diff --git a/examples/corelib/serialization/serialization.pro b/examples/corelib/serialization/serialization.pro index 9f0ced0282..e20fcb57fd 100644 --- a/examples/corelib/serialization/serialization.pro +++ b/examples/corelib/serialization/serialization.pro @@ -6,6 +6,4 @@ SUBDIRS = \ qtHaveModule(widgets) { SUBDIRS += streambookmarks - qtHaveModule(network): SUBDIRS += \ - rsslisting } |