mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-03 07:45:30 +08:00
6.5.3 clean
This commit is contained in:
@ -4,7 +4,7 @@
|
||||
if(NOT TARGET Qt6::Network)
|
||||
return()
|
||||
endif()
|
||||
if(NOT INTEGRITY)
|
||||
if(NOT INTEGRITY AND NOT ANDROID)
|
||||
qt_internal_add_example(dnslookup)
|
||||
endif()
|
||||
if(TARGET Qt6::Widgets)
|
||||
@ -18,6 +18,7 @@ if(TARGET Qt6::Widgets)
|
||||
qt_internal_add_example(multicastsender)
|
||||
qt_internal_add_example(fortuneclient)
|
||||
qt_internal_add_example(fortuneserver)
|
||||
qt_internal_add_example(rsslisting)
|
||||
endif()
|
||||
if(QT_FEATURE_processenvironment AND TARGET Qt6::Widgets)
|
||||
qt_internal_add_example(network-chat)
|
||||
|
@ -4,6 +4,10 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(dnslookup LANGUAGES CXX)
|
||||
|
||||
if (ANDROID)
|
||||
message(FATAL_ERROR "This project cannot be built on Android.")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
@ -79,7 +79,7 @@ CommandLineParseResult parseCommandLine(QCommandLineParser &parser, DnsQuery *qu
|
||||
if (query->nameServer.isNull()
|
||||
|| query->nameServer.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) {
|
||||
return { Status::Error,
|
||||
u"Bad nameserver address: %1"_qs.arg(nameserver) };
|
||||
u"Bad nameserver address: %1"_s.arg(nameserver) };
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,14 +88,14 @@ CommandLineParseResult parseCommandLine(QCommandLineParser &parser, DnsQuery *qu
|
||||
if (std::optional<QDnsLookup::Type> type = typeFromParameter(typeParameter))
|
||||
query->type = *type;
|
||||
else
|
||||
return { Status::Error, u"Bad record type: %1"_qs.arg(typeParameter) };
|
||||
return { Status::Error, u"Bad record type: %1"_s.arg(typeParameter) };
|
||||
}
|
||||
|
||||
const QStringList positionalArguments = parser.positionalArguments();
|
||||
if (positionalArguments.isEmpty())
|
||||
return { Status::Error, u"Argument 'name' missing."_qs };
|
||||
return { Status::Error, u"Argument 'name' missing."_s };
|
||||
if (positionalArguments.size() > 1)
|
||||
return { Status::Error, u"Several 'name' arguments specified."_qs };
|
||||
return { Status::Error, u"Several 'name' arguments specified."_s };
|
||||
query->name = positionalArguments.first();
|
||||
|
||||
return { Status::Ok };
|
||||
@ -202,7 +202,7 @@ int main(int argc, char *argv[])
|
||||
case Status::Ok:
|
||||
break;
|
||||
case Status::Error:
|
||||
std::fputs(qPrintable(parseResult.errorString.value_or(u"Unknown error occurred"_qs)),
|
||||
std::fputs(qPrintable(parseResult.errorString.value_or(u"Unknown error occurred"_s)),
|
||||
stderr);
|
||||
std::fputs("\n\n", stderr);
|
||||
std::fputs(qPrintable(parser.helpText()), stderr);
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example secureudpclient
|
||||
\title DTLS client
|
||||
\examplecategory {Networking}
|
||||
\ingroup examples-network
|
||||
\brief This example demonstrates how to implement client-side DTLS connections.
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example secureudpserver
|
||||
\title DTLS server
|
||||
\examplecategory {Networking}
|
||||
\ingroup examples-network
|
||||
\brief This examples demonstrates how to implement a simple DTLS server.
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/*!
|
||||
\example torrent
|
||||
\title Torrent Example
|
||||
\examplecategory {Networking}
|
||||
\ingroup examples-network
|
||||
\brief Demonstrates complex TCP/IP operations.
|
||||
|
||||
|
@ -8,18 +8,16 @@ qtHaveModule(widgets) {
|
||||
blockingfortuneclient \
|
||||
broadcastreceiver \
|
||||
broadcastsender \
|
||||
fortuneclient \
|
||||
fortuneserver \
|
||||
http \
|
||||
threadedfortuneserver \
|
||||
torrent \
|
||||
multicastreceiver \
|
||||
multicastsender
|
||||
multicastsender \
|
||||
rsslisting \
|
||||
threadedfortuneserver \
|
||||
torrent
|
||||
|
||||
qtConfig(processenvironment): SUBDIRS += network-chat
|
||||
|
||||
SUBDIRS += \
|
||||
fortuneclient \
|
||||
fortuneserver
|
||||
|
||||
qtConfig(ssl): SUBDIRS += securesocketclient
|
||||
qtConfig(dtls): SUBDIRS += secureudpserver secureudpclient
|
||||
qtConfig(sctp): SUBDIRS += multistreamserver multistreamclient
|
||||
|
38
examples/network/rsslisting/CMakeLists.txt
Normal file
38
examples/network/rsslisting/CMakeLists.txt
Normal file
@ -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}/network/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}"
|
||||
)
|
BIN
examples/network/rsslisting/doc/images/rsslisting.png
Normal file
BIN
examples/network/rsslisting/doc/images/rsslisting.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
129
examples/network/rsslisting/doc/src/rsslisting.qdoc
Normal file
129
examples/network/rsslisting/doc/src/rsslisting.qdoc
Normal file
@ -0,0 +1,129 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||
|
||||
/*!
|
||||
\example 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 rsslisting/main.cpp 0
|
||||
|
||||
\section1 The RSSListing class
|
||||
|
||||
\snippet 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 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 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 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 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
|
||||
*/
|
16
examples/network/rsslisting/main.cpp
Normal file
16
examples/network/rsslisting/main.cpp
Normal file
@ -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]
|
126
examples/network/rsslisting/rsslisting.cpp
Normal file
126
examples/network/rsslisting/rsslisting.cpp
Normal file
@ -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]
|
54
examples/network/rsslisting/rsslisting.h
Normal file
54
examples/network/rsslisting/rsslisting.h
Normal file
@ -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
|
8
examples/network/rsslisting/rsslisting.pro
Normal file
8
examples/network/rsslisting/rsslisting.pro
Normal file
@ -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
|
@ -11,8 +11,6 @@ QT_REQUIRE_CONFIG(ssl);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Q_INIT_RESOURCE(securesocketclient);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
if (!QSslSocket::supportsSsl()) {
|
||||
|
@ -9,8 +9,6 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
Q_INIT_RESOURCE(icons);
|
||||
|
||||
MainWindow window;
|
||||
window.show();
|
||||
|
||||
|
Reference in New Issue
Block a user