1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
|
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qnetworkreply.h"
#include "qnetworkreply_p.h"
#include <QtNetwork/qsslconfiguration.h>
QT_BEGIN_NAMESPACE
QNetworkReplyPrivate::QNetworkReplyPrivate()
: readBufferMaxSize(0),
operation(QNetworkAccessManager::UnknownOperation),
errorCode(QNetworkReply::NoError)
, isFinished(false)
{
// set the default attribute values
attributes.insert(QNetworkRequest::ConnectionEncryptedAttribute, false);
}
/*!
\class QNetworkReply
\since 4.4
\brief The QNetworkReply class contains the data and headers for a request
sent with QNetworkAccessManager
\reentrant
\ingroup network
\inmodule QtNetwork
The QNetworkReply class contains the data and meta data related to
a request posted with QNetworkAccessManager. Like QNetworkRequest,
it contains a URL and headers (both in parsed and raw form), some
information about the reply's state and the contents of the reply
itself.
QNetworkReply is a sequential-access QIODevice, which means that
once data is read from the object, it no longer kept by the
device. It is therefore the application's responsibility to keep
this data if it needs to. Whenever more data is received from the
network and processed, the readyRead() signal is emitted.
The downloadProgress() signal is also emitted when data is
received, but the number of bytes contained in it may not
represent the actual bytes received, if any transformation is done
to the contents (for example, decompressing and removing the
protocol overhead).
Even though QNetworkReply is a QIODevice connected to the contents
of the reply, it also emits the uploadProgress() signal, which
indicates the progress of the upload for operations that have such
content.
\note Do not delete the object in the slot connected to the
error() or finished() signal. Use deleteLater().
\sa QNetworkRequest, QNetworkAccessManager
*/
/*!
\enum QNetworkReply::NetworkError
Indicates all possible error conditions found during the
processing of the request.
\value NoError no error condition.
\note When the HTTP protocol returns a redirect no error will be
reported. You can check if there is a redirect with the
QNetworkRequest::RedirectionTargetAttribute attribute.
\value ConnectionRefusedError the remote server refused the
connection (the server is not accepting requests)
\value RemoteHostClosedError the remote server closed the
connection prematurely, before the entire reply was received and
processed
\value HostNotFoundError the remote host name was not found
(invalid hostname)
\value TimeoutError the connection to the remote server
timed out
\value OperationCanceledError the operation was canceled via calls
to abort() or close() before it was finished.
\value SslHandshakeFailedError the SSL/TLS handshake failed and the
encrypted channel could not be established. The sslErrors() signal
should have been emitted.
\value TemporaryNetworkFailureError the connection was broken due
to disconnection from the network, however the system has initiated
roaming to another access point. The request should be resubmitted
and will be processed as soon as the connection is re-established.
\value ProxyConnectionRefusedError the connection to the proxy
server was refused (the proxy server is not accepting requests)
\value ProxyConnectionClosedError the proxy server closed the
connection prematurely, before the entire reply was received and
processed
\value ProxyNotFoundError the proxy host name was not
found (invalid proxy hostname)
\value ProxyTimeoutError the connection to the proxy
timed out or the proxy did not reply in time to the request sent
\value ProxyAuthenticationRequiredError the proxy requires
authentication in order to honour the request but did not accept
any credentials offered (if any)
\value ContentAccessDenied the access to the remote
content was denied (similar to HTTP error 401)
\value ContentOperationNotPermittedError the operation requested
on the remote content is not permitted
\value ContentNotFoundError the remote content was not
found at the server (similar to HTTP error 404)
\value AuthenticationRequiredError the remote server requires
authentication to serve the content but the credentials provided
were not accepted (if any)
\value ContentReSendError the request needed to be sent
again, but this failed for example because the upload data
could not be read a second time.
\value ProtocolUnknownError the Network Access API cannot
honor the request because the protocol is not known
\value ProtocolInvalidOperationError the requested operation is
invalid for this protocol
\value UnknownNetworkError an unknown network-related
error was detected
\value UnknownProxyError an unknown proxy-related error
was detected
\value UnknownContentError an unknown error related to
the remote content was detected
\value ProtocolFailure a breakdown in protocol was
detected (parsing error, invalid or unexpected responses, etc.)
\sa error()
*/
/*!
\fn void QNetworkReply::sslErrors(const QList<QSslError> &errors)
This signal is emitted if the SSL/TLS session encountered errors
during the set up, including certificate verification errors. The
\a errors parameter contains the list of errors.
To indicate that the errors are not fatal and that the connection
should proceed, the ignoreSslErrors() function should be called
from the slot connected to this signal. If it is not called, the
SSL session will be torn down before any data is exchanged
(including the URL).
This signal can be used to display an error message to the user
indicating that security may be compromised and display the
SSL settings (see sslConfiguration() to obtain it). If the user
decides to proceed after analyzing the remote certificate, the
slot should call ignoreSslErrors().
\sa QSslSocket::sslErrors(), QNetworkAccessManager::sslErrors(),
sslConfiguration(), ignoreSslErrors()
*/
/*!
\fn void QNetworkReply::metaDataChanged()
\omit FIXME: Update name? \endomit
This signal is emitted whenever the metadata in this reply
changes. metadata is any information that is not the content
(data) itself, including the network headers. In the majority of
cases, the metadata will be known fully by the time the first
byte of data is received. However, it is possible to receive
updates of headers or other metadata during the processing of the
data.
\sa header(), rawHeaderList(), rawHeader(), hasRawHeader()
*/
/*!
\fn void QNetworkReply::finished()
This signal is emitted when the reply has finished
processing. After this signal is emitted, there will be no more
updates to the reply's data or metadata.
Unless close() has been called, the reply will be still be opened
for reading, so the data can be retrieved by calls to read() or
readAll(). In particular, if no calls to read() were made as a
result of readyRead(), a call to readAll() will retrieve the full
contents in a QByteArray.
This signal is emitted in tandem with
QNetworkAccessManager::finished() where that signal's reply
parameter is this object.
\note Do not delete the object in the slot connected to this
signal. Use deleteLater().
You can also use isFinished() to check if a QNetworkReply
has finished even before you receive the finished() signal.
\sa QNetworkAccessManager::finished(), isFinished()
*/
/*!
\fn void QNetworkReply::error(QNetworkReply::NetworkError code)
This signal is emitted when the reply detects an error in
processing. The finished() signal will probably follow, indicating
that the connection is over.
The \a code parameter contains the code of the error that was
detected. Call errorString() to obtain a textual representation of
the error condition.
\note Do not delete the object in the slot connected to this
signal. Use deleteLater().
\sa error(), errorString()
*/
/*!
\fn void QNetworkReply::uploadProgress(qint64 bytesSent, qint64 bytesTotal)
This signal is emitted to indicate the progress of the upload part
of this network request, if there's any. If there's no upload
associated with this request, this signal will not be emitted.
The \a bytesSent
parameter indicates the number of bytes uploaded, while \a
bytesTotal indicates the total number of bytes to be uploaded. If
the number of bytes to be uploaded could not be determined, \a
bytesTotal will be -1.
The upload is finished when \a bytesSent is equal to \a
bytesTotal. At that time, \a bytesTotal will not be -1.
\sa downloadProgress()
*/
/*!
\fn void QNetworkReply::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
This signal is emitted to indicate the progress of the download
part of this network request, if there's any. If there's no
download associated with this request, this signal will be emitted
once with 0 as the value of both \a bytesReceived and \a
bytesTotal.
The \a bytesReceived parameter indicates the number of bytes
received, while \a bytesTotal indicates the total number of bytes
expected to be downloaded. If the number of bytes to be downloaded
is not known, \a bytesTotal will be -1.
The download is finished when \a bytesReceived is equal to \a
bytesTotal. At that time, \a bytesTotal will not be -1.
Note that the values of both \a bytesReceived and \a bytesTotal
may be different from size(), the total number of bytes
obtained through read() or readAll(), or the value of the
header(ContentLengthHeader). The reason for that is that there may
be protocol overhead or the data may be compressed during the
download.
\sa uploadProgress(), bytesAvailable()
*/
/*!
\fn void QNetworkReply::abort()
Aborts the operation immediately and close down any network
connections still open. Uploads still in progress are also
aborted.
\sa close()
*/
/*!
Creates a QNetworkReply object with parent \a parent.
You cannot directly instantiate QNetworkReply objects. Use
QNetworkAccessManager functions to do that.
*/
QNetworkReply::QNetworkReply(QObject *parent)
: QIODevice(*new QNetworkReplyPrivate, parent)
{
}
/*!
\internal
*/
QNetworkReply::QNetworkReply(QNetworkReplyPrivate &dd, QObject *parent)
: QIODevice(dd, parent)
{
}
/*!
Disposes of this reply and frees any resources associated with
it. If any network connections are still open, they will be
closed.
\sa abort(), close()
*/
QNetworkReply::~QNetworkReply()
{
}
/*!
Closes this device for reading. Unread data is discarded, but the
network resources are not discarded until they are finished. In
particular, if any upload is in progress, it will continue until
it is done.
The finished() signal is emitted when all operations are over and
the network resources are freed.
\sa abort(), finished()
*/
void QNetworkReply::close()
{
QIODevice::close();
}
/*!
\internal
*/
bool QNetworkReply::isSequential() const
{
return true;
}
/*!
Returns the size of the read buffer, in bytes.
\sa setReadBufferSize()
*/
qint64 QNetworkReply::readBufferSize() const
{
return d_func()->readBufferMaxSize;
}
/*!
Sets the size of the read buffer to be \a size bytes. The read
buffer is the buffer that holds data that is being downloaded off
the network, before it is read with QIODevice::read(). Setting the
buffer size to 0 will make the buffer unlimited in size.
QNetworkReply will try to stop reading from the network once this
buffer is full (i.e., bytesAvailable() returns \a size or more),
thus causing the download to throttle down as well. If the buffer
is not limited in size, QNetworkReply will try to download as fast
as possible from the network.
Unlike QAbstractSocket::setReadBufferSize(), QNetworkReply cannot
guarantee precision in the read buffer size. That is,
bytesAvailable() can return more than \a size.
\sa readBufferSize()
*/
void QNetworkReply::setReadBufferSize(qint64 size)
{
Q_D(QNetworkReply);
d->readBufferMaxSize = size;
}
/*!
Returns the QNetworkAccessManager that was used to create this
QNetworkReply object. Initially, it is also the parent object.
*/
QNetworkAccessManager *QNetworkReply::manager() const
{
return d_func()->manager;
}
/*!
Returns the request that was posted for this reply. In special,
note that the URL for the request may be different than that of
the reply.
\sa QNetworkRequest::url(), url(), setRequest()
*/
QNetworkRequest QNetworkReply::request() const
{
return d_func()->request;
}
/*!
Returns the operation that was posted for this reply.
\sa setOperation()
*/
QNetworkAccessManager::Operation QNetworkReply::operation() const
{
return d_func()->operation;
}
/*!
Returns the error that was found during the processing of this
request. If no error was found, returns NoError.
\sa setError()
*/
QNetworkReply::NetworkError QNetworkReply::error() const
{
return d_func()->errorCode;
}
/*!
\since 4.6
Returns true when the reply has finished or was aborted.
\sa isRunning()
*/
bool QNetworkReply::isFinished() const
{
return d_func()->isFinished;
}
/*!
\since 4.6
Returns true when the request is still processing and the
reply has not finished or was aborted yet.
\sa isFinished()
*/
bool QNetworkReply::isRunning() const
{
return !isFinished();
}
/*!
Returns the URL of the content downloaded or uploaded. Note that
the URL may be different from that of the original request.
\sa request(), setUrl(), QNetworkRequest::url()
*/
QUrl QNetworkReply::url() const
{
return d_func()->url;
}
/*!
Returns the value of the known header \a header, if that header
was sent by the remote server. If the header was not sent, returns
an invalid QVariant.
\sa rawHeader(), setHeader(), QNetworkRequest::header()
*/
QVariant QNetworkReply::header(QNetworkRequest::KnownHeaders header) const
{
return d_func()->cookedHeaders.value(header);
}
/*!
Returns true if the raw header of name \a headerName was sent by
the remote server
\sa rawHeader()
*/
bool QNetworkReply::hasRawHeader(const QByteArray &headerName) const
{
Q_D(const QNetworkReply);
return d->findRawHeader(headerName) != d->rawHeaders.constEnd();
}
/*!
Returns the raw contents of the header \a headerName as sent by
the remote server. If there is no such header, returns an empty
byte array, which may be indistinguishable from an empty
header. Use hasRawHeader() to verify if the server sent such
header field.
\sa setRawHeader(), hasRawHeader(), header()
*/
QByteArray QNetworkReply::rawHeader(const QByteArray &headerName) const
{
Q_D(const QNetworkReply);
QNetworkHeadersPrivate::RawHeadersList::ConstIterator it =
d->findRawHeader(headerName);
if (it != d->rawHeaders.constEnd())
return it->second;
return QByteArray();
}
/*! \typedef QNetworkReply::RawHeaderPair
RawHeaderPair is a QPair<QByteArray, QByteArray> where the first
QByteArray is the header name and the second is the header.
*/
/*!
Returns a list of raw header pairs.
*/
const QList<QNetworkReply::RawHeaderPair>& QNetworkReply::rawHeaderPairs() const
{
Q_D(const QNetworkReply);
return d->rawHeaders;
}
/*!
Returns a list of headers fields that were sent by the remote
server, in the order that they were sent. Duplicate headers are
merged together and take place of the latter duplicate.
*/
QList<QByteArray> QNetworkReply::rawHeaderList() const
{
return d_func()->rawHeadersKeys();
}
/*!
Returns the attribute associated with the code \a code. If the
attribute has not been set, it returns an invalid QVariant (type QVariant::Null).
You can expect the default values listed in
QNetworkRequest::Attribute to be applied to the values returned by
this function.
\sa setAttribute(), QNetworkRequest::Attribute
*/
QVariant QNetworkReply::attribute(QNetworkRequest::Attribute code) const
{
return d_func()->attributes.value(code);
}
#ifndef QT_NO_OPENSSL
/*!
Returns the SSL configuration and state associated with this
reply, if SSL was used. It will contain the remote server's
certificate, its certificate chain leading to the Certificate
Authority as well as the encryption ciphers in use.
The peer's certificate and its certificate chain will be known by
the time sslErrors() is emitted, if it's emitted.
*/
QSslConfiguration QNetworkReply::sslConfiguration() const
{
QSslConfiguration config;
// determine if we support this extension
int id = metaObject()->indexOfMethod("sslConfigurationImplementation()");
if (id != -1) {
void *arr[] = { &config, 0 };
const_cast<QNetworkReply *>(this)->qt_metacall(QMetaObject::InvokeMetaMethod, id, arr);
}
return config;
}
/*!
Sets the SSL configuration for the network connection associated
with this request, if possible, to be that of \a config.
*/
void QNetworkReply::setSslConfiguration(const QSslConfiguration &config)
{
if (config.isNull())
return;
int id = metaObject()->indexOfMethod("setSslConfigurationImplementation(QSslConfiguration)");
if (id != -1) {
QSslConfiguration copy(config);
void *arr[] = { 0, © };
qt_metacall(QMetaObject::InvokeMetaMethod, id, arr);
}
}
/*!
\overload
\since 4.6
If this function is called, the SSL errors given in \a errors
will be ignored.
Note that you can set the expected certificate in the SSL error:
If, for instance, you want to issue a request to a server that uses
a self-signed certificate, consider the following snippet:
\snippet doc/src/snippets/code/src_network_access_qnetworkreply.cpp 0
Multiple calls to this function will replace the list of errors that
were passed in previous calls.
You can clear the list of errors you want to ignore by calling this
function with an empty list.
\sa sslConfiguration(), sslErrors(), QSslSocket::ignoreSslErrors()
*/
void QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors)
{
// do this cryptic trick, because we could not add a virtual method to this class later on
// since that breaks binary compatibility
int id = metaObject()->indexOfMethod("ignoreSslErrorsImplementation(QList<QSslError>)");
if (id != -1) {
QList<QSslError> copy(errors);
void *arr[] = { 0, © };
qt_metacall(QMetaObject::InvokeMetaMethod, id, arr);
}
}
#endif
/*!
If this function is called, SSL errors related to network
connection will be ignored, including certificate validation
errors.
Note that calling this function without restraint may pose a
security risk for your application. Use it with care.
This function can be called from the slot connected to the
sslErrors() signal, which indicates which errors were
found.
\sa sslConfiguration(), sslErrors(), QSslSocket::ignoreSslErrors()
*/
void QNetworkReply::ignoreSslErrors()
{
}
/*!
\internal
*/
qint64 QNetworkReply::writeData(const char *, qint64)
{
return -1; // you can't write
}
/*!
Sets the associated operation for this object to be \a
operation. This value will be returned by operation().
Note: the operation should be set when this object is created and
not changed again.
\sa operation(), setRequest()
*/
void QNetworkReply::setOperation(QNetworkAccessManager::Operation operation)
{
Q_D(QNetworkReply);
d->operation = operation;
}
/*!
Sets the associated request for this object to be \a request. This
value will be returned by request().
Note: the request should be set when this object is created and
not changed again.
\sa request(), setOperation()
*/
void QNetworkReply::setRequest(const QNetworkRequest &request)
{
Q_D(QNetworkReply);
d->request = request;
}
/*!
Sets the error condition to be \a errorCode. The human-readable
message is set with \a errorString.
Calling setError() does not emit the error(QNetworkReply::NetworkError)
signal.
\sa error(), errorString()
*/
void QNetworkReply::setError(NetworkError errorCode, const QString &errorString)
{
Q_D(QNetworkReply);
d->errorCode = errorCode;
setErrorString(errorString); // in QIODevice
}
/*!
\since 4.8
Sets the reply as \a finished.
After having this set the replies data must not change.
\sa isFinished()
*/
void QNetworkReply::setFinished(bool finished)
{
Q_D(QNetworkReply);
d->isFinished = finished;
}
/*!
Sets the URL being processed to be \a url. Normally, the URL
matches that of the request that was posted, but for a variety of
reasons it can be different (for example, a file path being made
absolute or canonical).
\sa url(), request(), QNetworkRequest::url()
*/
void QNetworkReply::setUrl(const QUrl &url)
{
Q_D(QNetworkReply);
d->url = url;
}
/*!
Sets the known header \a header to be of value \a value. The
corresponding raw form of the header will be set as well.
\sa header(), setRawHeader(), QNetworkRequest::setHeader()
*/
void QNetworkReply::setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
{
Q_D(QNetworkReply);
d->setCookedHeader(header, value);
}
/*!
Sets the raw header \a headerName to be of value \a value. If \a
headerName was previously set, it is overridden. Multiple HTTP
headers of the same name are functionally equivalent to one single
header with the values concatenated, separated by commas.
If \a headerName matches a known header, the value \a value will
be parsed and the corresponding parsed form will also be set.
\sa rawHeader(), header(), setHeader(), QNetworkRequest::setRawHeader()
*/
void QNetworkReply::setRawHeader(const QByteArray &headerName, const QByteArray &value)
{
Q_D(QNetworkReply);
d->setRawHeader(headerName, value);
}
/*!
Sets the attribute \a code to have value \a value. If \a code was
previously set, it will be overridden. If \a value is an invalid
QVariant, the attribute will be unset.
\sa attribute(), QNetworkRequest::setAttribute()
*/
void QNetworkReply::setAttribute(QNetworkRequest::Attribute code, const QVariant &value)
{
Q_D(QNetworkReply);
if (value.isValid())
d->attributes.insert(code, value);
else
d->attributes.remove(code);
}
QT_END_NAMESPACE
|