summaryrefslogtreecommitdiff
path: root/examples/corelib
diff options
context:
space:
mode:
authorØystein Heskestad <oystein.heskestad@qt.io>2023-03-03 17:41:43 +0100
committerØystein Heskestad <oystein.heskestad@qt.io>2023-03-21 14:49:09 +0100
commit10b4c06b4928d12addc7e55e4a6e5ed537a63942 (patch)
tree33f521c8fd692bf63618156aabb14dcb6009771c /examples/corelib
parent3c521e1fb42885e070bf07f36349a1e8cdb39e76 (diff)
downloadqtbase-10b4c06b4928d12addc7e55e4a6e5ed537a63942.tar.gz
Move rsslisting example into corelibe/serialization
The implementation of the stream-based XML parser resides in coreslib/serialization. Moving the rsslisting example there. Task-number: QTBUG-110647 Pick-to: 6.5 Change-Id: I862909e767301250750b6ee0d8ac7e20d6bad2b1 Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Diffstat (limited to 'examples/corelib')
-rw-r--r--examples/corelib/serialization/CMakeLists.txt3
-rw-r--r--examples/corelib/serialization/rsslisting/CMakeLists.txt38
-rw-r--r--examples/corelib/serialization/rsslisting/main.cpp26
-rw-r--r--examples/corelib/serialization/rsslisting/rsslisting.cpp211
-rw-r--r--examples/corelib/serialization/rsslisting/rsslisting.h55
-rw-r--r--examples/corelib/serialization/rsslisting/rsslisting.pro8
-rw-r--r--examples/corelib/serialization/serialization.pro5
7 files changed, 346 insertions, 0 deletions
diff --git a/examples/corelib/serialization/CMakeLists.txt b/examples/corelib/serialization/CMakeLists.txt
index 9609b0a107..0110eb8fff 100644
--- a/examples/corelib/serialization/CMakeLists.txt
+++ b/examples/corelib/serialization/CMakeLists.txt
@@ -4,3 +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()
diff --git a/examples/corelib/serialization/rsslisting/CMakeLists.txt b/examples/corelib/serialization/rsslisting/CMakeLists.txt
new file mode 100644
index 0000000000..405a01ce56
--- /dev/null
+++ b/examples/corelib/serialization/rsslisting/CMakeLists.txt
@@ -0,0 +1,38 @@
+# 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/main.cpp b/examples/corelib/serialization/rsslisting/main.cpp
new file mode 100644
index 0000000000..9337e5f352
--- /dev/null
+++ b/examples/corelib/serialization/rsslisting/main.cpp
@@ -0,0 +1,26 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+/*
+main.cpp
+
+Provides the main function for the RSS news reader example.
+*/
+
+#include <QtWidgets>
+
+#include "rsslisting.h"
+
+/*!
+ Create an application and a main widget. Open the main widget for
+ user input, and exit with an appropriate return value when it is
+ closed.
+*/
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ RSSListing *rsslisting = new RSSListing;
+ rsslisting->show();
+ return app.exec();
+}
diff --git a/examples/corelib/serialization/rsslisting/rsslisting.cpp b/examples/corelib/serialization/rsslisting/rsslisting.cpp
new file mode 100644
index 0000000000..9269be4080
--- /dev/null
+++ b/examples/corelib/serialization/rsslisting/rsslisting.cpp
@@ -0,0 +1,211 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+/*
+rsslisting.cpp
+
+Provides a widget for displaying news items from RDF news sources.
+RDF is an XML-based format for storing items of information (see
+http://www.w3.org/RDF/ for details).
+
+The widget itself provides a simple user interface for specifying
+the URL of a news source, and controlling the downloading of news.
+
+The widget downloads and parses the XML asynchronously, feeding the
+data to an XML reader in pieces. This allows the user to interrupt
+its operation, and also allows very large data sources to be read.
+*/
+
+
+#include <QtCore>
+#include <QtWidgets>
+#include <QtNetwork>
+
+#include "rsslisting.h"
+
+
+/*
+ Constructs an RSSListing widget with a simple user interface, and sets
+ up the XML reader to use a custom handler class.
+
+ The user interface consists of a line edit, a push button, and a
+ list view widget. The line edit is used for entering the URLs of news
+ sources; the push button starts the process of reading the
+ news.
+*/
+
+RSSListing::RSSListing(QWidget *parent)
+ : QWidget(parent), currentReply(0)
+{
+
+ lineEdit = new QLineEdit(this);
+ lineEdit->setText("http://blog.qt.io/feed/");
+
+ fetchButton = new QPushButton(tr("Fetch"), this);
+
+ treeWidget = new QTreeWidget(this);
+ connect(treeWidget, &QTreeWidget::itemActivated,
+ this, &RSSListing::itemActivated);
+ QStringList headerLabels;
+ headerLabels << tr("Title") << tr("Link");
+ treeWidget->setHeaderLabels(headerLabels);
+ treeWidget->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+
+ connect(&manager, &QNetworkAccessManager::finished,
+ this, &RSSListing::finished);
+
+ connect(lineEdit, &QLineEdit::returnPressed, this, &RSSListing::fetch);
+ connect(fetchButton, &QPushButton::clicked, this, &RSSListing::fetch);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+
+ QHBoxLayout *hboxLayout = new QHBoxLayout;
+
+ hboxLayout->addWidget(lineEdit);
+ hboxLayout->addWidget(fetchButton);
+
+ layout->addLayout(hboxLayout);
+ layout->addWidget(treeWidget);
+
+ setWindowTitle(tr("RSS listing example"));
+ resize(640,480);
+}
+
+/*
+ Starts the network request and connects the needed signals
+*/
+void RSSListing::get(const QUrl &url)
+{
+ QNetworkRequest request(url);
+ if (currentReply) {
+ currentReply->disconnect(this);
+ currentReply->deleteLater();
+ }
+ currentReply = manager.get(request);
+ connect(currentReply, &QNetworkReply::readyRead, this, &RSSListing::readyRead);
+ connect(currentReply, &QNetworkReply::metaDataChanged, this, &RSSListing::metaDataChanged);
+ connect(currentReply, &QNetworkReply::errorOccurred, this, &RSSListing::error);
+}
+
+/*
+ Starts fetching data from a news source specified in the line
+ edit widget.
+
+ The line edit is made read only to prevent the user from modifying its
+ contents during the fetch; this is only for cosmetic purposes.
+ The fetch button is disabled, the list view is cleared, and we
+ define the last list view item to be 0, meaning that there are no
+ existing items in the list.
+
+ A URL is created with the raw contents of the line edit and
+ a get is initiated.
+*/
+
+void RSSListing::fetch()
+{
+ lineEdit->setReadOnly(true);
+ fetchButton->setEnabled(false);
+ treeWidget->clear();
+
+ xml.clear();
+
+ QUrl url(lineEdit->text());
+ get(url);
+}
+
+void RSSListing::metaDataChanged()
+{
+ QUrl redirectionTarget = currentReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
+ if (redirectionTarget.isValid()) {
+ get(redirectionTarget);
+ }
+}
+
+/*
+ Reads data received from the RDF source.
+
+ We read all the available data, and pass it to the XML
+ stream reader. Then we call the XML parsing function.
+*/
+
+void RSSListing::readyRead()
+{
+ int statusCode = currentReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ if (statusCode >= 200 && statusCode < 300) {
+ QByteArray data = currentReply->readAll();
+ xml.addData(data);
+ parseXml();
+ }
+}
+
+/*
+ Finishes processing an HTTP request.
+
+ The default behavior is to keep the text edit read only.
+
+ If an error has occurred, the user interface is made available
+ to the user for further input, allowing a new fetch to be
+ started.
+
+ If the HTTP get request has finished, we make the
+ user interface available to the user for further input.
+*/
+
+void RSSListing::finished(QNetworkReply *reply)
+{
+ Q_UNUSED(reply);
+ lineEdit->setReadOnly(false);
+ fetchButton->setEnabled(true);
+}
+
+
+/*
+ Parses the XML data and creates treeWidget items accordingly.
+*/
+void RSSListing::parseXml()
+{
+ while (!xml.atEnd()) {
+ xml.readNext();
+ if (xml.isStartElement()) {
+ if (xml.name() == u"item")
+ linkString = xml.attributes().value("rss:about").toString();
+ 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);
+
+ titleString.clear();
+ linkString.clear();
+ }
+
+ } 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();
+ }
+}
+
+/*
+ Open the link in the browser
+*/
+void RSSListing::itemActivated(QTreeWidgetItem * item)
+{
+ QDesktopServices::openUrl(QUrl(item->text(1)));
+}
+
+void RSSListing::error(QNetworkReply::NetworkError)
+{
+ qWarning("error retrieving RSS feed");
+ currentReply->disconnect(this);
+ currentReply->deleteLater();
+ currentReply = 0;
+}
diff --git a/examples/corelib/serialization/rsslisting/rsslisting.h b/examples/corelib/serialization/rsslisting/rsslisting.h
new file mode 100644
index 0000000000..81c655f677
--- /dev/null
+++ b/examples/corelib/serialization/rsslisting/rsslisting.h
@@ -0,0 +1,55 @@
+// 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 <QBuffer>
+#include <QXmlStreamReader>
+#include <QUrl>
+
+
+QT_BEGIN_NAMESPACE
+class QLineEdit;
+class QTreeWidget;
+class QTreeWidgetItem;
+class QPushButton;
+QT_END_NAMESPACE
+
+class RSSListing : public QWidget
+{
+ Q_OBJECT
+public:
+ RSSListing(QWidget *widget = nullptr);
+
+public slots:
+ void fetch();
+ void finished(QNetworkReply *reply);
+ void readyRead();
+ void metaDataChanged();
+ void itemActivated(QTreeWidgetItem * item);
+ void error(QNetworkReply::NetworkError);
+
+private:
+ void parseXml();
+ void get(const QUrl &url);
+
+ QXmlStreamReader xml;
+ QString currentTag;
+ QString linkString;
+ QString titleString;
+
+ QNetworkAccessManager manager;
+ QNetworkReply *currentReply;
+
+ QLineEdit *lineEdit;
+ QTreeWidget *treeWidget;
+ QPushButton *fetchButton;
+
+};
+
+#endif
+
diff --git a/examples/corelib/serialization/rsslisting/rsslisting.pro b/examples/corelib/serialization/rsslisting/rsslisting.pro
new file mode 100644
index 0000000000..7619755b8f
--- /dev/null
+++ b/examples/corelib/serialization/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]/corelib/serialization/rsslisting
+INSTALLS += target
diff --git a/examples/corelib/serialization/serialization.pro b/examples/corelib/serialization/serialization.pro
index 7651444f19..f36b467783 100644
--- a/examples/corelib/serialization/serialization.pro
+++ b/examples/corelib/serialization/serialization.pro
@@ -3,3 +3,8 @@ SUBDIRS = \
cbordump \
convert \
savegame
+
+qtHaveModule(widgets) {
+ qtHaveModule(network): SUBDIRS += \
+ rsslisting
+}